01
—
前言
在传统的中小公司里面,尤其是以企业内部的办公系统、REP系统,或者体量不是很大的互联网公司里面,搭建一套单库和单表足以应对生产的业务数据量了。而在一些互联网大公司里面,单表每天有上100w的数据业务增量时,就要考虑分库分表的策略了。否则,无论是数据的存储、访问、更新等操作,单库和单表都会影响系统和数据库的性能。
02
—
什么是分库分表?
分库:从单个数据库拆分成多个数据库的过程,将数据散落在多个数据库中。分表:从单张表拆分成多张表的过程,将数据散落在多张表内。
常见的分库分表有2种方式,一种是:垂直切分,另一种是:水平切分。
垂直切分:一个表字段很多,包含了很多业务量信息,若分模块可把该表按业务划分成若干不同的小表。如:电商系统中的某个业务表同时包含了会员、订单、支付、交易和地址等信息,这时可按这些小的业务模块单独划分成小表,以会员表、订单表、支付表、交易和地址表通过某一个关联属性字段进行关联。
水平切分:业务体量很大,但是单表字段不是很复杂,业务单一,每日数据增量大及读写操作频繁的时候,当平常的索引和从库已无法满足系统和数据性能时,可考虑水平切分。
03
—
业界成熟的分库分表组件
cobar:Cobar是阿里巴巴研发的关系型数据的分布式处理系统(Amoeba的升级版,该产品成功替代了原先基于Oracle的数据存储方案,目前已经接管了3000+个MySQL数据库的schema,平均每天处理近50亿次的SQL执行请求。
https://github.com/alibaba/cobar/
TDDL:淘宝根据自身的业务特点开发的TDDL(Taobao Distributed Data Layer )框架,主要解决了分库分表对应用的透明化以及异构数据库之间的数据复制,它是一个基于集中式配置的 jdbc datasource 实现,具有主备,读写分离,动态数据库配置等功能。
https://github.com/alibaba/tb_tddl
atlas:是Qihoo 360基于Mysql Proxy开发的一个Mysql中间件,据称每天承载读写请求数达几十亿,可以实现分表、分库(sharding版本)、读写分离、数据库连接池等功能,缺点是没有实现跨库分表功能,需要在客户端使用分库逻辑,目前Atlas不活跃。
https://github.com/Qihoo360/Atlas
sharding-jdbc:最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 ShardingSphere,2020年4月16正式成为 Apache 软件基金会的顶级项目。
Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。
https://shardingsphere.apache.org/
mycat:MyCat 是目前最流行的基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用 MySQL 原生协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信,其核心功能是分库分表。配合数据库的主从模式还可实现读写分离。
https://mycat.sourceforge.net/
以上这些就是目前业界一些常用的分库分表开源组件,选用哪个组件来进行分库和分表,具体要看我们的业务场景,没有最好的只有更适合业务场景组件。
04
—
ShardingJdbc的分库分表策略
4.1 架构
在项目内引入 Sharding-JDBC 的依赖,我们的业务代码在操作数据库的时候,就会通过 Sharding-JDBC 的代码连接到数据库
分库分表的一些核心动作,比如 SQL 解析,路由,执行,结果处理,都是由它来完成的。它工作在客户端
4.2 分片策略
分片策略包含:分片键和分片算法,分片算法是需要自定义的,可以用于分库,也可以用于分表
Sharding-JDBC 提供了 5 种分片策略,这些策略全部继承自 ShardingStrategy
1)行表达式分片策略
对应 InlineShardingStrategy 类,只支持单分片键,提供对=和 IN 操作的支持,行内表达式的配置比较简单#例如:
${begin..end}表示范围区间 ${[unit1, unit2, unit_x]}表示枚举值 t_user_$->{u_id % 8} 表示 t_user 表根据 u_id 模 8,而分成 8 张表,表名称为t_user_0 到 t_user_7
行表达式中如果出现连续多个->{ expression }表达式,整个表达式最终的结果将会根据每个子表达式的结果进行笛卡尔组合
#例如,以下行表达式:
{['db1', 'db2']}_table{1..3}
#最终会解析为:
db1_table1, db1_table2, db1_table3, db2_table1, db2_table2, db2_table3
2)标准分片策略
对应的是StandardShardingStrategy类
标准分片策略只支持单分片键,提供了提供 PreciseShardingAlgorithm 和RangeShardingAlgorithm两个分片算法,分别对应于SQL语句中的=, IN和BETWEEN AND
如果要使用标准分片策略,必须要实现PreciseShardingAlgorithm,用来处理=和IN 的分片,RangeShardingAlgorithm 是可选的,如果没有实现,SQL 语句会发到所有的数据节点上执行
3)复合分片策略
对应 ComplexShardingStrategy 类,可以支持等值查询和范围查询
复合分片策略支持多分片键,提供了 ComplexKeysShardingAlgorithm,分片算法需要自己实现
比如:根据日期和 ID 两个字段分片,每个月 3 张表,先根据日期,再根据 ID 取模
4)Hint分片策略
对应 HintShardingStrategy类,通过 Hint 而非 SQL 解析的方式分片的策略,有点类似于 Mycat 的指定分片注解
5)不分片策略
对应 NoneShardingStrategy类,不分片的策略
4.3 多种多样的配置方式
1)Java 配置
把数据源和分片策略都写在 Java Config 中,特点是:非常灵活,我们可以实现各种定义的分片策略,但是缺点是:如果把数据源、策略都配置在 Java Config中,就出现了硬编码,在修改的时候比较麻烦
2)Spring Boot配置
直接使用 Spring Boot 的 application.properties 来配置,这个要基于starter 模块,org.apache.shardingsphere 的包还没有 starter,只有 io.shardingsphere的包有 starter
把数据源和分库分表策略都配置在 properties 文件中,这种方式配置比较简单,但是不能实现复杂的分片策略,不够灵活
3)yml配置
使用 Spring Boot 的 yml 配置(shardingjdbc.yml),也要依赖 starter模块,当然我们也可以结合不同的配置方式,比如把分片策略放在 JavaConfig 中,数据源配置在 yml 中或 properties 中。
4.4 分布式全局ID
在分布式系统中,一旦数据库做了分库分表之后,原单表(如mysql)中的主键ID不再是唯一键了,这时需要设置和选取一个字段作为全局的唯一ID,这就涉及到分布式中的另一个话题:无中心化分布式主键(包括UUID、snowflake雪花、LEAF)。
总体上,需要配置的就是这两个:数据源和分片策略,当然分片策略又包括分库的策略和分表的策略
05
—
总结
sharding-jdbc是一款轻量级Java框架,以jar包形式提供服务,是属于客户端产品不需要额外部署,它相当于是个增强版的JDBC驱动;sharding-jdbc的兼容性也非常强大,适用于任何基于JDBC的ORM框架,如:JPA,Hibernate,Mybatis,Spring JDBC Template或直接使用的JDBC。完美兼容任何第三方的数据库连接池,如:DBCP,C3P0,BoneCP,Druid,HikariCP等,几乎对所有关系型数据库都支持。不难发现确实是比较强大的一款工具,而且它对项目的侵入性很小,几乎不用做任何代码层的修改,也无需修改SQL语句,只需配置待分库分表的数据表即可。