sharding-sphere源码分析之基础应用篇

技术

做数据库分库分表的中间件有很多,如mycat、DRDS、TDDL等,它们的实现方式大多是作为一个数据库代理,是一个实现了MySQL协议的服务器。而sharding-sphere是一款开源的可以轻量级地像使用mysql-jdbc-connector那样来操作分库分表数据。同时它也提供了proxy模块,提供了代理的功能。而且它的orchestration模块提供了更加高级的数据管理功能。

本篇主要介绍一下sharding-sphere官方demo介绍的几种使用示例。

下载sharding-sphere-example-dev模块

进入sharding-spring-boot-mybatis-example模块,先来通过boot和mybatis整合版本整理下基本功能: 关于springboot autoconfigure部分,看下面的sharding-jdbc-spring-boot-starter的截图:

picture.image

这部分不再多说,无非就是通过springboot starter加载dataSource和ShardingRule和一些基本信息。

功能分析

看下该模块下的配置文件:

picture.image

我们可以看到在sharding data方面的常用功能是:

  • sharding databases
  • sharding tables
  • sharding databases and tables
  • master-slave
  • sharding & master-slave

我们来一一分析。

sharding-databases

  1. 将模块中的application.properties中的spring.profiles.active=sharding-databases,设置成分库模式,
  2. 对应的application-sharding-databases.properties中配置为:

      1. `spring.shardingsphere.datasource.names=ds_0,ds_1`
2. 
3. `spring.shardingsphere.datasource.ds_0.type=com.zaxxer.hikari.HikariDataSource`
4. `spring.shardingsphere.datasource.ds_0.driver-class-name=com.mysql.jdbc.Driver`
5. `spring.shardingsphere.datasource.ds_0.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
6. `spring.shardingsphere.datasource.ds_0.username=root`
7. `spring.shardingsphere.datasource.ds_0.password=`
8. 
9. `spring.shardingsphere.datasource.ds_1.type=com.zaxxer.hikari.HikariDataSource`
10. `spring.shardingsphere.datasource.ds_1.driver-class-name=com.mysql.jdbc.Driver`
11. `spring.shardingsphere.datasource.ds_1.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
12. `spring.shardingsphere.datasource.ds_1.username=root`
13. `spring.shardingsphere.datasource.ds_1.password=`
14. 
15. `spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id`
16. `spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}`
17. 
18. `spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order`
19. `spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id`
20. `spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE`
21. `spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123`
22. `spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item`
23. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id`
24. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE`
25. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123`


    
  • default-database-strategy.inline.sharding-column=user_id表示按user_id进行分片。
  • default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}这里配置的是分库的策略。
  • 这段配置主要是分库模式的,会将数据按照对应的策略存入不同的库中去。上面配置的两个库的名字分别是ds_0和ds_1,分片算法的分片键是user_id,分片算法是对user_id 取模算法,user_id % 2。数据会根据算法插入到ds_0和ds_1两个库中去。
  1. 我们看下这个example的执行过程:

      1. `@ComponentScan("org.apache.shardingsphere.example.common.mybatis")`
2. `@MapperScan(basePackages = "org.apache.shardingsphere.example.common.mybatis.repository")`
3. `@SpringBootApplication(exclude = JtaAutoConfiguration.class)`
4. `public class SpringBootMybatisMain {`
5. 
6. `public static void main(final String[] args) {`
7. `try (ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringBootMybatisMain.class, args)) {`
8. `CommonService commonService = applicationContext.getBean(SpringPojoService.class);`
9. `commonService.initEnvironment();`
10. `commonService.processSuccess();`
11. `commonService.cleanEnvironment();`
12. `}`
13. `}`
14. `}`


    

这里我们主要关注下插入的流程(代码中注释掉删除数据和表的逻辑),看下SpringPojoServiceImpl中的insertData方法:

picture.image

这个方法是向库中插入了10条数据,user_id的取值为1-10,我们看看插入的结果:

demo_ds_0对应配置中的ds_0,结果为:

picture.image

demo_ds_1对应配置中的ds_1,结果为:

picture.image

其中t_order_item表中的情况和t_order的情况一样,都是user_id为偶数的数据进入了demo_ds_0库对应的表中,user_id为奇数的数据进入到了demo_ds_1库中。

example中对应的删除数据的逻辑也与插入数据一样,不再多说。

sharding tables

  1. 修改配置:

picture.image 2. 数据库中的分表方案,对应的application-sharding-tables.properties中对应的配置为:


      1. `spring.shardingsphere.datasource.names=ds`
2. 
3. `spring.shardingsphere.datasource.ds.type=com.zaxxer.hikari.HikariDataSource`
4. `spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver`
5. `spring.shardingsphere.datasource.ds.jdbc-url=jdbc:mysql://localhost:3306/demo_ds?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
6. `spring.shardingsphere.datasource.ds.username=root`
7. `spring.shardingsphere.datasource.ds.password=`
8. 
9. `spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds.t_order_$->{0..1}`
10. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id`
11. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}`
12. `spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id`
13. `spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE`
14. `spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123`
15. `spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds.t_order_item_$->{0..1}`
16. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id`
17. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}`
18. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id`
19. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE`
20. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123`


    

关于配置:

  • spring.shardingsphere.datasource.names配置的是需要sharding的数据库名称,对应的是下面配置的库demo_ds;
  • actual-data-nodes=ds.t_order_$->{0..1}表示是对ds这个库进行分表,可以看到这里没有配置分库策略;
  • sharding-column=order_id和table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}表示是按order_id对表进行分片,分片规则是对2取余,也就是奇偶分片,order_id为奇数的数据进入t_order_1表,偶数的进入t_order_0表。
  • t_order_item为前缀的表的规则和t_order为前缀的表的规则一样。
  • key-generator部分是主键生成策略的配置。
  1. 我们主要关注插入数据的逻辑(删除的逻辑与插入数据的路由规则相同),先注释掉代码中的清数据的逻辑,运行org.apache.shardingsphere.example.sharding.spring.boot.mybatis.SpringBootMybatisMain之后,结果如下:

picture.image

picture.image

其中t_order_item与t_order的情况相同。可以看到在这种sharding方式下,是将数据在同一个库中进行分表存储的。

sharding databases and tables

  1. 修改配置

picture.image 2. application-sharding-databases-tables.properties中的配置内容为:


      1. `spring.shardingsphere.datasource.names=ds_0,ds_1`
2. 
3. `spring.shardingsphere.datasource.ds_0.type=com.zaxxer.hikari.HikariDataSource`
4. `spring.shardingsphere.datasource.ds_0.driver-class-name=com.mysql.jdbc.Driver`
5. `spring.shardingsphere.datasource.ds_0.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
6. `spring.shardingsphere.datasource.ds_0.username=root`
7. `spring.shardingsphere.datasource.ds_0.password=`
8. 
9. `spring.shardingsphere.datasource.ds_1.type=com.zaxxer.hikari.HikariDataSource`
10. `spring.shardingsphere.datasource.ds_1.driver-class-name=com.mysql.jdbc.Driver`
11. `spring.shardingsphere.datasource.ds_1.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
12. `spring.shardingsphere.datasource.ds_1.username=root`
13. `spring.shardingsphere.datasource.ds_1.password=`
14. 
15. `spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id`
16. `spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}`
17. 
18. `spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}`
19. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id`
20. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}`
21. `spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id`
22. `spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE`
23. `spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123`
24. `spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item_$->{0..1}`
25. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id`
26. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}`
27. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id`
28. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE`
29. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123`


    

关于配置:

  • spring.shardingsphere.datasource.names=ds_0,ds_1是目前使用的库是ds_0,ds_1与下面配置的dataSource相对应。
  • default-database-strategy.inline.sharding-column.sharding-column=user_id表示以user_id为库分片键,default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}表示按奇偶策略来划分库。
  • actual-data-nodes=ds_>0..1.t_order_->{0..1}.t\_order\_->{0..1} 配置同时进行分库分表的格式。
  • t_order.table-strategy.inline.sharding-column=order_id配置t_order表的表分片键,t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}配置t_order的表分片策略。
  • key-generator部分是配置主键生成策略。

master-slave

主从模式

  1. 修改配置
  2. picture.image
  3. application-master-slave.properties的配置信息

      1. `spring.shardingsphere.datasource.names=ds_master,ds_slave_0,ds_slave_1`
2. 
3. `spring.shardingsphere.datasource.ds_master.type=com.zaxxer.hikari.HikariDataSource`
4. `spring.shardingsphere.datasource.ds_master.driver-class-name=com.mysql.jdbc.Driver`
5. `spring.shardingsphere.datasource.ds_master.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_master?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
6. `spring.shardingsphere.datasource.ds_master.username=root`
7. `spring.shardingsphere.datasource.ds_master.password=123456`
8. 
9. `spring.shardingsphere.datasource.ds_slave_0.type=com.zaxxer.hikari.HikariDataSource`
10. `spring.shardingsphere.datasource.ds_slave_0.driver-class-name=com.mysql.jdbc.Driver`
11. `spring.shardingsphere.datasource.ds_slave_0.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_slave_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
12. `spring.shardingsphere.datasource.ds_slave_0.username=root`
13. `spring.shardingsphere.datasource.ds_slave_0.password=123456`
14. 
15. `spring.shardingsphere.datasource.ds_slave_1.type=com.zaxxer.hikari.HikariDataSource`
16. `spring.shardingsphere.datasource.ds_slave_1.driver-class-name=com.mysql.jdbc.Driver`
17. `spring.shardingsphere.datasource.ds_slave_1.jdbc-url=jdbc:mysql://localhost:3306/demo_ds_slave_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
18. `spring.shardingsphere.datasource.ds_slave_1.username=root`
19. `spring.shardingsphere.datasource.ds_slave_1.password=123456`
20. 
21. `spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin`
22. `spring.shardingsphere.masterslave.name=ds_ms`
23. `spring.shardingsphere.masterslave.master-data-source-name=ds_master`
24. `spring.shardingsphere.masterslave.slave-data-source-names=ds_slave_0,ds_slave_1`


    
  • 配置了三个数据源,一主两从。
  • 从库的负载方式配置为round_robin。
  • 其中主从库数据的复制需要自己解决,可以采用mysql官方的主从复制方案可者使用第三方的读取binlog的中间件如阿里开源的canal等。
  1. 数据插入部分的执行结果:

picture.image 2. 可见数据在程序中是写入主库的,查询的时候是可以按照配置的从库负载方式在从库间进行路由的,当然也可以强制走主库,关于这些在之前的一篇文章(sharding-jdbc源码之读写分离和从库负载)中已经详细介绍过,有不明白的可以去翻阅。

sharding & master-slave

主从模式下的分片

  1. 修改配置

picture.image 2. application-sharding-master-slave.properties中的配置


      1. `spring.shardingsphere.datasource.names=ds_master_0,ds_master_1,ds_master_0_slave_0,ds_master_0_slave_1,ds_master_1_slave_0,ds_master_1_slave_1`
2. 
3. `spring.shardingsphere.datasource.ds_master_0.type=com.zaxxer.hikari.HikariDataSource`
4. `spring.shardingsphere.datasource.ds_master_0.driver-class-name=com.mysql.jdbc.Driver`
5. `spring.shardingsphere.datasource.ds_master_0.jdbc-url=jdbc:mysql://localhost:3306/ds_master_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
6. `spring.shardingsphere.datasource.ds_master_0.username=root`
7. `spring.shardingsphere.datasource.ds_master_0.password=123456`
8. 
9. `spring.shardingsphere.datasource.ds_master_0_slave_0.type=com.zaxxer.hikari.HikariDataSource`
10. `spring.shardingsphere.datasource.ds_master_0_slave_0.driver-class-name=com.mysql.jdbc.Driver`
11. `spring.shardingsphere.datasource.ds_master_0_slave_0.jdbc-url=jdbc:mysql://localhost:3306/ds_master_0_slave_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
12. `spring.shardingsphere.datasource.ds_master_0_slave_0.username=root`
13. `spring.shardingsphere.datasource.ds_master_0_slave_0.password=123456`
14. `spring.shardingsphere.datasource.ds_master_0_slave_1.type=com.zaxxer.hikari.HikariDataSource`
15. `spring.shardingsphere.datasource.ds_master_0_slave_1.driver-class-name=com.mysql.jdbc.Driver`
16. `spring.shardingsphere.datasource.ds_master_0_slave_1.jdbc-url=jdbc:mysql://localhost:3306/ds_master_0_slave_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
17. `spring.shardingsphere.datasource.ds_master_0_slave_1.username=root`
18. `spring.shardingsphere.datasource.ds_master_0_slave_1.password=123456`
19. 
20. `spring.shardingsphere.datasource.ds_master_1.type=com.zaxxer.hikari.HikariDataSource`
21. `spring.shardingsphere.datasource.ds_master_1.driver-class-name=com.mysql.jdbc.Driver`
22. `spring.shardingsphere.datasource.ds_master_1.jdbc-url=jdbc:mysql://localhost:3306/ds_master_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
23. `spring.shardingsphere.datasource.ds_master_1.username=root`
24. `spring.shardingsphere.datasource.ds_master_1.password=123456`
25. 
26. `spring.shardingsphere.datasource.ds_master_1_slave_0.type=com.zaxxer.hikari.HikariDataSource`
27. `spring.shardingsphere.datasource.ds_master_1_slave_0.driver-class-name=com.mysql.jdbc.Driver`
28. `spring.shardingsphere.datasource.ds_master_1_slave_0.jdbc-url=jdbc:mysql://localhost:3306/ds_master_1_slave_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
29. `spring.shardingsphere.datasource.ds_master_1_slave_0.username=root`
30. `spring.shardingsphere.datasource.ds_master_1_slave_0.password=123456`
31. `spring.shardingsphere.datasource.ds_master_1_slave_1.type=com.zaxxer.hikari.HikariDataSource`
32. `spring.shardingsphere.datasource.ds_master_1_slave_1.driver-class-name=com.mysql.jdbc.Driver`
33. `spring.shardingsphere.datasource.ds_master_1_slave_1.jdbc-url=jdbc:mysql://localhost:3306/ds_master_1_slave_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8`
34. `spring.shardingsphere.datasource.ds_master_1_slave_1.username=root`
35. `spring.shardingsphere.datasource.ds_master_1_slave_1.password=123456`
36. 
37. `spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id`
38. `spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}`
39. 
40. `spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}`
41. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id`
42. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}`
43. `spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id`
44. `spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE`
45. `spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123`
46. `spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds_$->{0..1}.t_order_item_$->{0..1}`
47. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id`
48. `spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item_$->{order_id % 2}`
49. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.column=order_item_id`
50. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.type=SNOWFLAKE`
51. `spring.shardingsphere.sharding.tables.t_order_item.key-generator.props.worker.id=123`
52. 
53. `spring.shardingsphere.sharding.master-slave-rules.ds_0.master-data-source-name=ds_master_0`
54. `spring.shardingsphere.sharding.master-slave-rules.ds_0.slave-data-source-names=ds_master_0_slave_0, ds_master_0_slave_1`
55. `spring.shardingsphere.sharding.master-slave-rules.ds_1.master-data-source-name=ds_master_1`
56. `spring.shardingsphere.sharding.master-slave-rules.ds_1.slave-data-source-names=ds_master_1_slave_0, ds_master_1_slave_1`


    

关于配置:

  • 总共配置了6个数据源,两个master分别各自对应两个slave。
  • 其中主从库数据的复制需要自己解决,可以采用mysql官方的主从复制方案可者使用第三方的读取binlog的中间件如阿里开源的canal等。
  • 真正的sharding是针对两个master来的,然后master中的数据会使用用户选择的数据同步方案复制到slave库中。
  • 对两个master库的sharding方式为:

      1. `spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=user_id`
2. `spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds_$->{user_id % 2}`


    

通过user_id为分片键,按奇偶分库。

  • 对两个master库进行分表的配置为:

      1. `spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds_$->{0..1}.t_order_$->{0..1}`
2. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id`
3. `spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2}`


    

分片键为order_id,方式为奇偶分表。

  1. 对于数据写入的执行结果:

picture.image

picture.image

可以看到先是根据userid进行分库,然后对应库中再按orderid进行分表。

结语

到这里,关于sharding-sephere常用的分库分表使用示例都分析完毕了。下面总结几点:

  • sharding是大数据量下的一种常用处理方法,像elasticsearch、solrCloud、mongodb的分片模式等都是采用sharding的方式来处理大量数据的。
  • sharding一般是使用指定的分片键来进行分片路由的,sharding后数据处理的流程几乎都要经过解析->重写->路由->执行->结果归并这几个阶段。
  • sharding-sphere是支持针对数据库进行分库、分表、分片和读写分离处理等多种功能的中间件。
  • 它不同于mycat和DRDS这种中间代理服务转发处理数据库请求的中间件,它是比较轻量级直接在jdbc层和db交互的,使用它就像使用一种普通数据源一样简单。当然它目前的sharding-proxy模块也提供了代理的功能。

如果只是应用的话,本篇就基本上够用了。接下来会对上面的example中的这几种方式从源码角度进行分析,针对每个example的解析->重写->路由->执行->结果归并这几个阶段都会进行详细讲述。

参考

https://github.com/apache/incubator-shardingsphere

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
DevOps 在字节移动研发中的探索和实践
在日益复杂的APP工程架构下,如何保证APP能高效开发,保障团队效能和工程质量?本次将结合字节内部应用的事件案例,介绍DevOps团队对移动研发效能建设的探索和思考。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论