ShardingSphere源码阅读(一)

ShardingSphere源码阅读(一)

ShardingSphere源码阅读前的准备


前言

为什么会选择阅读ShardingSphere的源码呢?其实可以说机缘巧合下,在之前报的课程中有人带,并且是一个小团体进行阅读还有分享的,并且以前没有源码阅读经验,这次参与刚好作为一次开始,大家互相监督可以坚持下去这是最重要的。
引用老师说的一句话:“一个人可以走很快,一群人却可以走很远”,坚持努力总不会错的,共勉!

一、ShardingSphere是什么?

想学习一样新的东西,无非就是以下五步,前四步就够,第五步就是看个人的了

  1. 首先需知道这个东西的存在,如果连知道都不知道,更不要说学习,所以我知道了ShardingSphere,那么就完成第一步
  2. 知道了ShardingSphere后,那么就是去了解它到底是干什么的,能干什么的,在官网都能看到
    1.1、ShardingSphere官网:https://shardingsphere.apache.org/
    1.2、GitHub地址:https://github.com/apache/shardingsphere
  3. 初步了解ShardingSphere的工作原理功能效果后,为了加深印象,就需要根据官方的文档去跑demo,这一步很重要,如果不愿意跑一次demo,那么就没后面的事情的,亲身体验效果才能更容易领悟,也为阅读源码走出第一步。
  4. 跑完demo之后,就是思考为什么会得到这个结果,这个结果是怎么实现的,这里就是进入源码阅读的入口,需要思考这个过程,带着疑问深入了解,去源码查找答案
  5. 达到了一定程度,就是需要理解实现原理,这步是拆解整个框架的组成,并且思考着能不能自己也实现一个类似功能的工具,不在本文的范围(其实这里就达到架构师的门槛和成为开源社区项目committer的重要一环)

二、跑Demo

ShardingSphere有JDBC,Proxy和UI三部分,分别看看

1.ShardingSphere-JDBC

ShardingSphere的demo发现了五种不同的类型:

  • 分库(SHARDING_DATABASES)
  • 分表(SHARDING_TABLES)
  • 分库分表(SHARDING_DATABASES_AND_TABLES)
  • 读写分离(READWRITE_SPLITTING)
  • 分库读写分离(SHARDING_READWRITE_SPLITTING)
  • 外加一种特殊的类型:加密(Encrypt_Databases)

1.1.API接口实现

实例化代码如下:

public static DataSource newInstance(final ShardingType shardingType) throws SQLException {
        switch (shardingType) {
            case SHARDING_DATABASES:
                return new ShardingDatabasesConfigurationPrecise().getDataSource();
            case SHARDING_TABLES:
                return new ShardingTablesConfigurationPrecise().getDataSource();
            case SHARDING_DATABASES_AND_TABLES:
                return new ShardingDatabasesAndTablesConfigurationPrecise().getDataSource();
            case READWRITE_SPLITTING:
                return new ReadwriteSplittingConfiguration().getDataSource();
            case SHARDING_READWRITE_SPLITTING:
                return new ShardingReadwriteSplittingConfigurationPrecise().getDataSource();
            default:
                throw new UnsupportedOperationException(shardingType.name());
        }
    }

根据不同的shardingType去选择实例化数据源,里面处理实例化数据源之外,还需要分库分表,读写分离等规则,这些规则决定了如何实现相应的功能,选择分库分表作为解析,代码如下:

private ShardingRuleConfiguration createShardingRuleConfiguration() {
        ShardingRuleConfiguration result = new ShardingRuleConfiguration();
        //不同表的分表规则,第一个是order表
        result.getTables().add(getOrderTableRuleConfiguration());
        //这个是order_item表
        result.getTables().add(getOrderItemTableRuleConfiguration());
        //分表的所有logic表放到这个组中
        result.getBindingTableGroups().add("t_order, t_order_item");
        result.getBroadcastTables().add("t_address");
        result.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("user_id", "inline"));
        result.setDefaultTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "standard_test_tbl"));
        Properties props = new Properties();
        //分库算法,具体基于哪个字段作为分库标志
        props.setProperty("algorithm-expression", "demo_ds_${user_id % 2}");
        result.getShardingAlgorithms().put("inline", new ShardingSphereAlgorithmConfiguration("INLINE", props));
        result.getShardingAlgorithms().put("standard_test_tbl", new ShardingSphereAlgorithmConfiguration("STANDARD_TEST_TBL", new Properties()));
        //自动key生成使用什么算法,这里使用雪花算法
        result.getKeyGenerators().put("snowflake", new ShardingSphereAlgorithmConfiguration("SNOWFLAKE", getProperties()));
        return result;
    }
    
    private static ShardingTableRuleConfiguration getOrderTableRuleConfiguration() {
        ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("t_order", "demo_ds_${0..1}.t_order_${[0, 1]}");
        result.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("order_id", "snowflake"));
        return result;
    }
    
    private static ShardingTableRuleConfiguration getOrderItemTableRuleConfiguration() {
        ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("t_order_item", "demo_ds_${0..1}.t_order_item_${[0, 1]}");
        result.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("order_item_id", "snowflake"));
        return result;
    }
    
    private static Map<String, DataSource> createDataSourceMap() {
        //具体需要绑定多少个数据源,每个数据源都需要写入map
        Map<String, DataSource> result = new HashMap<>();
        result.put("demo_ds_0", DataSourceUtil.createDataSource("demo_ds_0"));
        result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1"));
        return result;
    }
    
    private static Properties getProperties() {
        Properties result = new Properties();
        result.setProperty("worker-id", "123");
        return result;
    }

其实上述的参数在官网都能找到,也有教如何配置,这个就是ShardingSphere-JDBC的API接口实现,根据官网参数和修改参数去多跑几次Demo,可以更清晰每一个有用的参数,其它的shardingType基本都是大同小异

1.2.配置文件实现

配置文件主要就是yaml(可以写成yml)文件,用配置文件写好数据源和规则,加载配置文件就可以,这些配置属性在ShardingSphere官网也是有的,可以参考官方文档

dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password:
  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/demo_ds_1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
    username: root
    password:

rules:
# 重点:这个就是控制这个yaml文件实现那个功能的,-!SHARDING 就是分库分表规则
- !SHARDING
  tables:
    t_order: 
      actualDataNodes: ds_${0..1}.t_order_${0..1}
      tableStrategy: 
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_inline
      keyGenerateStrategy:
        column: order_id
        keyGeneratorName: snowflake
    t_order_item:
      actualDataNodes: ds_${0..1}.t_order_item_${0..1}
      tableStrategy:
        standard:
          shardingColumn: order_id
          shardingAlgorithmName: t_order_item_inline
      keyGenerateStrategy:
        column: order_item_id
        keyGeneratorName: snowflake
  bindingTables:
    - t_order,t_order_item
  broadcastTables:
    - t_address
  defaultDatabaseStrategy:
    standard:
      shardingColumn: user_id
      shardingAlgorithmName: database_inline
  defaultTableStrategy:
    none:
  
  shardingAlgorithms:
    database_inline:
      type: INLINE
      props:
        algorithm-expression: ds_${user_id % 2}
    t_order_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_${order_id % 2}
    t_order_item_inline:
      type: INLINE
      props:
        algorithm-expression: t_order_item_${order_id % 2}
  
  keyGenerators:
    snowflake:
      type: SNOWFLAKE
      props:
          worker-id: 123

props:
  sql-show: false

至于加密Encrypt_Databases其实和其他区别不大,只不过需要注意支持的加密算法,和配置算法的规则,这些在官方文档都可以查到,不展开来讲了

2.ShardingSphere-Proxy

由于ShardingSphere-JDBC每次修改都需要重新package jar包,才能生效,在维护方面不是很便利,所以就出现了ShardingSphere-Proxy,proxy是一个中间件,需要单独启动一个服务才能使用,也是使用配置文件yaml实现功能的,一共需要两份及以上的配置文件

2.1.server.yaml,是用于启动和配置proxy服务的

#mode:
#  type: Cluster
#  repository:
#    type: ZooKeeper
#    props:
#      namespace: governance_ds
#      serverLists: localhost:2181
#      retryIntervalMilliseconds: 500
#      timeToLiveSeconds: 60
#      maxRetries: 3
#      operationTimeoutMilliseconds: 500
#  overwrite: false
  
rules:
#重点,这个是proxy的logic表,可以连接的,用这个表关联实体表,统一从这里进行操作就可以了
  - !AUTHORITY
    users:
      - root@:root
      - sharding@:sharding
    provider:
      type: NATIVE

props:
  max-connections-size-per-query: 1
  executor-size: 16  # Infinite by default.
  proxy-frontend-flush-threshold: 128  # The default value is 128.
    # LOCAL: Proxy will run with LOCAL transaction.
    # XA: Proxy will run with XA transaction.
    # BASE: Proxy will run with B.A.S.E transaction.
  proxy-transaction-type: LOCAL
  proxy-opentracing-enabled: false
  proxy-hint-enabled: false
  sql-show: false
  check-table-metadata-enabled: false

从上面配置看到一大段给注释的配置,看得出是有关集群的,还是使用ZooKeeper进行服务注册发现的

2.2.config-xxx.yaml

这些配置就是关于分库分表,读写分离等的规则的配置文件,可以直接复用ShardingSphere—JDBC配置文件,其实是一致的,如果有修改需要重启

启动proxy前,把所有配置都完成后,直接启动,然后业务代码那边的数据源,配置为proxy的server.yaml的logic库表就可以和正常数据库一样使用了

3.ShardingSphere-UI

在ShardingSphere-Proxy中提到两个点,一是proxy是独立运行的中间件服务,二是留了一个注释的配置,是关于集群的。

有关第一点,单个服务就会有不可用的时候,那么当proxy服务不可用时,业务也不可用了,所以就需要高可用,引入第二点,搭配ZooKeeper实现集群达到高可用,而ShardingSphere-UI就是用可视化界面对上述的进行管理,并且是实时更新配置文件的,刷新后即可用,这是ShardingSphere-JDBC和ShardingSphere-Proxy所不能达到的,具体如下图
ShardingSphere源码阅读(一)
ShardingSphere源码阅读(一)


总结

先要阅读源码,首先去跑一下官方的Demo,目的是对ShardingSphere有一定的熟悉后,才能开展后续,当然有ShardingSphere的开发使用经验的人可以省略此步,在这个过程中把思考一下怎么实现的,为什么这样实现的,然后记录这些问题,带到后面源码阅读中去查找答案,会发现阅读起来才会有感觉,不然根本不知道如何下手,怎么去阅读,那么就很难坚持下去,而我因为有小组鞭策,并且交流方法,并且找到适合自己阅读源码方式,坚持下了,后面就是关于源码阅读的文章了。带着问题去阅读总不会比其他办法更加差了。

PS: ShardingSphere里面的库、表、字段这些不能用数据库的关键字,这样会出现一些未知错误的,如果一定要用这些关键字,那么就需要处理好,像mysql需要加反单引去区分是字符串

上一篇:【Mac】快速删除指定文件夹下的.DS_Store文件


下一篇:TP5.0实现 图片本地化并完成缩略图的制作