聊聊 Sharding-JDBC 分库分表(一)
大家好,我是不才陈某~
这是《ShardingSphere 进阶》专栏的第一篇文章,介绍一下Sharding-JDBC实现分库分表的详细配置。
分库分表带来的问题
关于什么是分库分表这里不再细说了,相信大家都知道,有不清楚的可以看我之前的文章:聊聊分库分表
从单一表、单一库切分成多库、多表对于性能的提升是必然的,但是同时也带来了一些问题。
1. 分布式事务问题
由于垂直分库、水平分库,将数据分摊在不同库中,甚至不同的服务器上,势必带来了分布式事务的问题。
对于单库单表的事务很好控制,分布式事务的控制却是非常头疼,但是好在现在已经有成熟的解决方案,想要了解的可以看我之前的文章:七种分布式事务解决方案
2. 跨节点关联join问题
在切分之前关联查询非常简单,直接SQL JOIN便能解决,但是切分之后数据分摊在不同的节点上,此时JOIN就比较麻烦了,因此切分之后尽量避免JOIN。
解决这一问题的有些方法:
1、全局表
这种很好理解,对于一些全局需要关联的表可以在每个数据节点上都存储一份,一般是一些数据字典表。
“全局表在Sharding-JDBC称之为广播表”
2、字段冗余
这是一种典型的反范式设计,为了避免关联JOIN,可以将一些冗余字段保存,比如订单表保存userId时,可以将userName也一并保存,这样就避免了和User表的关联JOIN了。
“字段冗余这种方案存在数据一致性问题”
3、数据组装
这种还是比较好理解的,直接不使用JOIN关联,分两次查询,从第一次的结果集中找出关联数据的唯一标识,然后再次去查询,最后对得到的数据进行组装
“需要进行手动组装,数据很大的情况对CPU、内存有一定的要求”
4、绑定表
对于相互关联的数据节点,通过分片规则将其切分到同一个库中,这样就可以直接使用SQL的JOIN 进行关联查询。
“Sharding-JDBC中称之为绑定表,比如订单表和用户表的绑定”
3. 跨节点分页、排序、函数问题
对于跨数据节点进行分页、排序或者一些聚合函数,筛选出来的仅仅是针对当前节点,比如排序,仅仅能够保证在单一数据节点上是有序,并不能保证在所有节点上都是有序的,需要将各个节点的数据的进行汇总重新手动排序。
“Sharding-JDBC 正是 按照上述流程进行分页、排序、聚合”
4. 全局主键避重问题
单库单表一般都是使用的自增主键,但是在切分之后每个自增主键将无法使用,因为这样会导致数据主键重复,因此必须重新设计主键。
目前主流的分布式主键生成方案如下:
1、UUID
UUID应该是大家最为熟悉的一种方案,优点非常明显本地生成,性能高,缺点也很明显,太长了存储耗空间,查询也非常耗性能,另外UUID的无序性将会导致InnoDB下的数据位置变动。
2、Snowflake
Twitter开源的由64位整数组成分布式ID,性能较高,并且在单机上递增。
“不再详细介绍,更多信息自行查找资料”
3、UidGenerator
UidGenerator是百度开源的分布式ID生成器,其基于雪花算法实现。具体参考:
“https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md”
4、Leaf
Leaf是美团开源的分布式ID生成器,能保证全局唯一,趋势递增,但需要依赖关系数据库、Zookeeper等中间件。具体参考:
“https://tech.meituan.com/2017/04/21/mt-leaf.html”
5. 数据迁移、扩容问题
当业务高速发展,面临性能和存储的瓶颈时,才会考虑分片设计,此时就不可避免的需要考虑历史数据迁移的问题。一般做法是先读出历史数据,然后按指定的分片规则再将数据写入到各个分片节点中。此外还需要根据当前的数据量和QPS,以及业务发展的速度,进行容量规划,推算出大概需要多少分片。
如果采用数值范围分片,只需要添加节点就可以进行扩容了,不需要对分片数据迁移。如果采用的是数值取模分片,则考虑后期的扩容问题就相对比较麻烦。
“分库分表虽然提升了性能,但是在切分过程中一定要考虑上述总结的5种问题。”
文章转自公众号:码猿技术专栏