原创不易,请多多支援!对Java技术感兴趣的童鞋请关注我,后面技术分享更精彩。
介绍
mysql几乎成为现在后台专案开发的标配。虽然流行,但还是有弊端。单表超过5000w资料时,查询效能将急剧下降。一般业务发展到这个时候,分库分表将是绕不开的话题。但针对一些小的团队,自己设计分库分表逻辑,可能存在难度高、bug多的问题。使用mycat,又有些大材小用。文字将推荐一款小巧、便捷的分库分表元件 --- sharding-jdbc。希望在专案开发中对广大coder有所帮助。sharding-jdbc最初是当当内部的一个架构元件,经过实际专案的身经百炼,不断抽象提取其通用性,开源出来的一套分库分表框架实现。现已贡献给Apache开源基金会,属于ShardingSphere中的一部分。
sharding-jdbc以jar包依赖的方式整合到专案中,在jdbc层实现sql解析、路由和归并等操作,对业务层透明。仅需简单配置,原有业务程式码几乎无需改动即可使用。
架构
由于本文着重推荐sharding-jdbc,对ShardingSphere将不做过多介绍,有兴趣额的童鞋可以去以下官网了解。https://shardingsphere.apache.org/document/current/cn/overview/
sharding-jdbc定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全相容JDBC和各种ORM框架。
适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。基于任何第三方的数据库连线池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。支援任意实现JDBC规范的数据库。目前支援MySQL,Oracle,SQLServer和PostgreSQL。
上图中sharding-jdbc应用于jdbc层,对业务层无感知,可以不影响原有逻辑的情况下平滑使用。当然,分散式分库、分表存在她的局限性,分库表最好是单表查询,不建议掺杂多表的join、union等操作。
使用
为了便于演示,这里只以订单表的分表使用作为样例。开始前,请先了解以下两个概念。逻辑表
水平拆分的资料表的相同逻辑和资料结构表的总称。例:订单资料根据主键尾数拆分为10张表,分别是order_0到order_9,他们的逻辑表名为order。
真实表
在分片的数据库中真实存在的物理表。即上个示例中的order_0到order_9。
jar依赖
这里以springboot专案为例。专案中新增以下starter依赖。org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
规则配置
在spring application.yml档案中新增以下配置spring:
main:
# sharding-jdbc定义了重复的dataSource资料来源bean,启动时必须新增以下值
allow-bean-definition-overriding: true
# sharding-jdbc 分库、分表配置
shardingsphere:
datasource:
names: ds0
ds0:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/dctl_demo
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
sharding:
# default-database-strategy:
# inline:
# sharding-column: user_id
# algorithm-expression: ds$->{user_id % 2}
tables:
#分表的逻辑表表名
order:
#分表的物理表节点,资料来源ds0下的order0...order9,共10张表
actual-data-nodes: ds0.order$->{0..9}
table-strategy:
inline:
#分片规则对应列,即以user_id值作为分片规则的列
sharding-column: user_id
#分片按user_id列和10取模运算,路由到对应的order0...9的表
algorithm-expression: order$->{user_id % 10}
由于本文仅涉及分表,不涉及分库。所以分库配置default-database-strategy被遮蔽。
有分库需求的对应着规则修改即可。
表结构
新建逻辑表,表结构如下CREATE TABLE `order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT \'订单id\',
`user_id` bigint(20) unsigned NOT NULL COMMENT \'使用者id\',
`product_id` bigint(20) unsigned NOT NULL COMMENT \'产品id\',
`price` decimal(8,2) DEFAULT \'0.00\' COMMENT \'商品价格\',
`create_time` datetime DEFAULT NULL COMMENT \'建立时间\',
`create_by` varchar(255) DEFAULT NULL COMMENT \'建立人\',
`update_time` datetime DEFAULT NULL COMMENT \'更新时间\',
`update_by` varchar(255) DEFAULT NULL COMMENT \'更新人\',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
按上面逻辑表,新建订单对应的10张物理表。
测试服务
新增订单controller。启动工程,模拟post请求,构建订单。
响应结果
数据库记录检视
由于分表规则以user_id来分片,并按10取模路由实际表。测试资料是user_id=9,取模后定位到order9这张表中。检视相应表,下图可见资料已经成功写入到相应表中。
总结
到此,整个整合已全部完成,是否感觉对专案业务的侵入性很小?简单、快捷,分库分表so easy!再来回顾下整个整合过程
首先依赖引入。定义分库分表的分片规则,配置档案表、分片列、分片表示式等修改。数据库建立逻辑表和真实表。按原有方式编写sql程式码逻辑。看上去很简单,但使用时一定要清楚sharding-jdbc的使用场景,过多的sql join切记不要使用,否则多库多表查询时,可能造成框架的笛卡尔集扫描,导致每个库、每张表都被查询,最终严重影响系统性能。
若业务需求避免不了多表查询,请把join的sql拆成多个,先查分表的值。用查到的值作为条件,再到另一个sql中查询。
最后,希望本文对有耐心看到最后的童鞋有所帮助。有相应问题和意见,欢迎指正。