sharding 分表分库

demo地址:https://gitee.com/luci-fast/mybatis-plus-sharding

最近进行技术重构,考虑到服务拆分与分表分库,首先考虑的是mycat,毕竟mycat是代理,对于代码方面来说,能做到零侵入。
但是了解了一下发现mycat社区活跃度,与一些数据分区难点的解决方案,个人觉得都不是很理想,就又看了sharding sphere.

sharding sphere首先是轻量级的,而且对于java来说,只是多集成jar包,对jdbc,jpa,mybatis都支持,社区活跃度还高,便沉下心来看了几天,
发现代码侵入性真的很低很低,因此把这次集成过程记录下来

**组件版本:**

springboot 2.1.1

mysql5.7

mybatis-plus 国人开发的mybatis增强工具,集成使用简单,一直关注着,很赞的组件。链接:https://mp.baomidou.com/

shardingsphere jdbc 4.0.4-RC1  4.x版本是加入apache组织后的发布版本,有很多改动。

shardingsphere proxy 最新版本  用于开发运维工具,分表分库以后,对于数据的查询我们很难像单库单表一样迅速定位,简单来说就是,
使用navicat连接 shardingsphere proxy服务,这样就可以很方便直观的操作数据库,因为官方也介绍proxy性能损耗大,适合做运维工具。

shardingsphere官方链接: https://shardingsphere.apache.org/

**集成过程**
-   1.分库分表依据

        因为架构是基于微服务的,所以每个服务有自己的数据库,根据每个服务的未来理想化的数据进行预估。每张表量在千万以下。
        比如:订单,预计一千亿数据,那么就分为32库,每个库72张表,最终一共两千多张表,一千亿数据平均下来,每张表只有几百万。
        接下来 我们以订单相关的几张表为例,进行分表分库:订单表  订单明细表 订单字典表 订单子表(一些业务可能会有)
        
-   2.分片相关概念

        逻辑表- 业务逻辑表。  例如:订单表o_order 订单明细表o_order_item  因为量大 都需要分库
        真实表- 真实的数据分片表。 例如:o_order23
        数据节点- 数据分片的最小单元。由数据源名称和数据表组成。例如: odb1.o_order23
        绑定表- 具有数据关联的表,建立绑定关系,则在一个库下,可以进行join。 例如:订单数据与订单明细,如果在一个库下,则可以join查询。
        广播表- 一些静态信息表。 广播分发到每一个数据源,方便查询join。例如:订单字典表。
        不分片表- 不需要分片的表。 例如:订单子表,一些业务订单,可能拆分成子订单,但这种情况少之又少,数据很小,无需分表分库。
        分片键- 进行分表分库的字段。 例如:根据商户id进行分库,根据订单id进行分表。
        分片算法- 例如:商户id取模36得到数据源 订单id取模72得到表
        分片策略- sphere提供了几种策略,这里采用最简单的行表达式
        分布式id- 使用内置的雪花算法,但是workid没有想好在docker环境下如何处理
        分布式事务- 使用内置xa支持
        sql支持与不支持- 请查看官方文档
        路由原理- 请查看官方文档 尤其是带不带分片键的区别
        以上概念均可在官方文档查看。接下来进行实际操作,实现对订单与订单明细表的36库72表
        
-     3.创建数据库

        在mysql创建37个数据库 其中odb为默认数据源 存放不需要分片的表
        CREATE DATABASE `odb` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb0` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb2` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb3` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb4` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb5` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb6` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb7` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb8` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb9` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb10` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb11` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb12` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb13` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb14` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb15` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb16` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb17` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb18` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb19` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb20` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb21` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb22` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb23` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb24` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb25` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb26` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb27` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb28` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb29` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb30` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb31` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb32` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb33` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb34` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        CREATE DATABASE `odb35` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
        设置最大连接数
        set GLOBAL max_connections=1000;
        
-     4.导入pom

       
            org.apache.shardingsphere
            sharding-jdbc-spring-boot-starter
            4.0.0-RC1
       

       
       
            org.apache.shardingsphere
            sharding-jdbc-spring-namespace
            4.0.0-RC1
       

        其它包省略
        
-     5.建立sharding规则

        spring:
          shardingsphere:
            props:
              # 打印sql
              sql.show: true
              check:
                table:
                  metadata:
                    # 是否在启动时检查分表元数据一致性
                    enabled: false
            datasource:
              # 数据源汇总
              names: odb,odb0,odb1,odb2,odb3,odb4,odb5,odb6,odb7,odb8,odb9,odb10,odb11,odb12,odb13,odb14,odb15,odb16,odb17,odb18,odb19,odb20,odb21,odb22,odb23,odb24,odb25,odb26,odb27,odb28,odb29,odb30,odb31,odb32,odb33,odb34,odb35
              # 真实数据源连接
              odb:
                type: com.zaxxer.hikari.HikariDataSource
                driver-class-name: com.mysql.jdbc.Driver
                jdbcUrl: jdbc:mysql://localhost:3306/odb?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT&allowPublicKeyRetrieval=true
                username: root
                password: root
              odb0:
                type: com.zaxxer.hikari.HikariDataSource
                driver-class-name: com.mysql.jdbc.Driver
                jdbcUrl: jdbc:mysql://localhost:3306/odb0
                username: root
                password: root
                # 其中省略 1-34
              odb35:
                type: com.zaxxer.hikari.HikariDataSource
                driver-class-name: com.mysql.jdbc.Driver
                jdbcUrl: jdbc:mysql://localhost:3306/odb35
                username: root
                password: root
            # 分片规则
            sharding:
              # 默认数据源
              default-data-source-name: odb
              # 默认主键生成策略
              default-key-generator:
                type: SNOWFLAKE
                column: id
                worker:
                  id: order # 雪花算法workid  还没想好多实例docker情况下如何配置
                max:
                  tolerate:
                    time:
                      difference:
                        milliseconds: 1
              # 默认分库策略 根据门店id 取模 这样虽然做不到数据平均分摊,但是每个门店的订单都统一在一个库下,方便join。
              default-database-strategy:
                inline:
                  shardingColumn: shop_id
                  algorithmExpression: odb$->{shop_id % 36}
              # 广播表
              broadcastTables:
                - o_dict
              # 绑定表关系 分片策略相同的表,即可建立绑定关系
              bindingTables:
                - o_order,o_order_item
              # 具体表策略
              tables:
                # 订单表 根据订单id取模
                o_order:
                  actual-data-nodes: odb$->{0..35}.o_order$->{0..71}
                  table-strategy:
                    inline:
                      sharding-column: id
                      algorithm-expression: o_order$->{id % 72}

                #  订单表详情 根据订单id取模 
                o_order_item:
                  actual-data-nodes: odb$->{0..35}.o_order_item$->{0..71}
                  table-strategy:
                    inline:
                      sharding-column: order_id
                      algorithm-expression: o_order_item$->{order_id % 72}
                      
- 6 建表

        项目中 orm框架去映射逻辑表,在执行sql时,会自动映射到真实物理表
        启动服务,就可以利用mybatis执行建表语句
         CREATE TABLE IF NOT EXISTS
        o_order (
                id BIGINT AUTO_INCREMENT,
                shop_id BIGINT NOT NULL,
                code VARCHAR(50),
                create_time timestamp(0),
                PRIMARY KEY (id)
            );
        DROP TABLE IF EXISTS `o_order_child`;
        CREATE TABLE `o_order_child`  (
          `id` bigint(20) NOT NULL,
          `order_id` bigint(20) NULL DEFAULT NULL,
          `shop_id` bigint(20) NULL DEFAULT NULL,
          PRIMARY KEY (`id`) USING BTREE
        ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

        DROP TABLE IF EXISTS `o_dict`;
        CREATE TABLE `o_dict`  (
          `id` bigint(20) NOT NULL,
          `shop_id` bigint(20) NULL DEFAULT NULL,
          `key` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
          PRIMARY KEY (`id`) USING BTREE
        ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
        
            CREATE TABLE
            IF NOT EXISTS o_order_item (
                id BIGINT AUTO_INCREMENT,
                order_id BIGINT,
                shop_id BIGINT NOT NULL,
                NAME VARCHAR (50),
                PRIMARY KEY (id)
            );
            然后会发现,odb0到odb35 每个库都有72张订单表,72张订单明细表。每个库都有一张字典表。odb中有子单表。
            
- 6 sharding sphere proxy服务 

        通过官方的docker拉取服务,总是启动失败,未找到原因。因此直接下载了最新的客户端。将分片规则copy进去。就可启动。
        默认端口3307 设置用户名密码  即可用navicat连接。
        连接成功后,即可进行运维操作。比如建表等等。但是发现并未显示不分库的表,不过sql可以正常执行。
        
- 7 flyway继承

        失败,因为flyway默认会读取系统表的信息,而我们的sharding时jdbc代理的逻辑表,没有真实表
        
- 8 读写分离

        未加入,可自行根据官方文档参考加入
        
- 8 分库事务

         @Transactional配合TransactionTypeHolder.set(TransactionType.XA);即可实现。
         其实官方文档中有@ShardingTransactionType(TransactionType.LOCAL)注解,但本人未下载到相应jar包。
            @Transactional(rollbackFor = Exception.class)
            public void batchAdd() {
                TransactionTypeHolder.set(TransactionType.XA);
                for (int i=41;i<=60; i++) {
                    Order order  = new Order();
                    order.setId(new Long(i));
                    order.setShopId(new Long(i));
                    order.setCode(i + "test");
                    orderMapper.insert(order);
                    if (i == 50) {
                        throw new RuntimeException();
                    }
                    for(int j=1;j<=10; j++) {
                        OrderItem orderItem = new OrderItem();
                        orderItem.setId(new Long((i*10)+j));
                        orderItem.setOrderId(order.getId());
                        orderItem.setName("明细 "+ j);
                        orderItem.setShopId(new Long(i));
                        itemMapper.insert(orderItem);
                    }
                }
            }

demo地址:https://gitee.com/luci-fast/mybatis-plus-sharding

sharding 分表分库_第1张图片

 

sharding 分表分库_第2张图片

 

sharding 分表分库_第3张图片

sharding 分表分库_第4张图片

sharding 分表分库_第5张图片

 

sharding 分表分库_第6张图片

sharding 分表分库_第7张图片

sharding 分表分库_第8张图片

sharding 分表分库_第9张图片

你可能感兴趣的:(Sharding,Web项目,DB)