分库分表之ShardingSphere(二)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 分库分表之ShardingSphere
实现读写分离

环境配置:使用mall库为主库,mall_01、mall_02为从库,前提是MySQL数据库需要提前做好读写分离相关配置

1、读写分离配置

server.port=8099
spring.application.name=sharding-jdbc-demo
spring.profiles.active=dev
#指定数据库连接信息 一主两从
spring.shardingsphere.datasource.names=master,slave0,slave1
spring.shardingsphere.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.master.url=jdbc:mysql://xxx:3306/mall?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=xxx
spring.shardingsphere.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.slave0.url=jdbc:mysql://xxx:3306/mall_1?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.slave0.username=root
spring.shardingsphere.datasource.slave0.password=xxx
spring.shardingsphere.datasource.slave1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.slave1.url=jdbc:mysql://xxx:3306/mall_2?serverTimezone=GMT%2B8
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=xxx
# 配置从节点负载均衡策略,采用轮询机制
spring.shardingsphere.masterslave.load-balance-algorithm-type=round_robin
# 配置主从名称
spring.shardingsphere.masterslave.name=ms
# 配置数据源的读写分离
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=master
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=slave0,slave1
#sql输出日志
spring.shardingsphere.props.sql.show=true
# 一个实体类对应两张表,覆盖
spring.main.allow-bean-definition-overriding=true

2、测试读

查找成功

3、测试写

写入主库成功,会自动同步到两个从库,然后查询的时候通过负载均衡轮询到一个子库进行查询

Sharding-Proxy

它是一个数据库的代理端,代理数据库我们只用访问它就行了,通过访问代理数据库来简化分库分表的操作

环境配置

1、安装包下载解压

https://archive.apache.org/dist/shardingsphere/4.1.0/apache-shardingsphere-4.1.0-sharding-proxy-bin.tar.gz

2、在conf目录下,修改server.yaml文件,去掉这一部分的注释

3、需要手动的把mysql驱动的jar包放到lib目录下否则程序无法运行

4、配置分库分表

修改config-sharding.yaml文件

schemaName: sharding_db
dataSources:
 ds_0:
   url: jdbc:mysql://121.43.33.150:3306/mall_1?serverTimezone=UTC&useSSL=false
   username: root
   password: xxx
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
 ds_1:
   url: jdbc:mysql://121.43.33.150:3306/mall_2?serverTimezone=UTC&useSSL=false
   username: root
   password: xxx
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
shardingRule:
 tables:
 #t_order表规则 可配置多个表
   t_order:
     actualDataNodes: ds_${0..1}.t_order_${0..1}
     tableStrategy:
       inline:
         shardingColumn: order_id
         algorithmExpression: t_order_${order_id % 2}
     keyGenerator:
       type: SNOWFLAKE
       column: order_id
 bindingTables:
   - t_order
 defaultDatabaseStrategy:
   inline:
     shardingColumn: order_number
     algorithmExpression: ds_${order_number % 2}
 defaultTableStrategy:
   none:

5、启动Sharding-Proxy

执行bin目录下的start.sh文件

./start.sh 3308

显示Active表示成功了

6、mysql登陆

mysql -uroot -proot  -P3308 -h127.0.0.1

分库分表

配置规则

schemaName: sharding_db
dataSources:
 ds_0:
   url: jdbc:mysql://127.0.0.1:3306/lottery_01?serverTimezone=Asia/Shanghai&useSSL=false
   username: root
   password: 123456
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
 ds_1:
   url: jdbc:mysql://127.0.0.1:3306/lottery_02?serverTimezone=Asia/Shanghai&useSSL=false
   username: root
   password: 123456
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
shardingRule:
 tables:
 #t_order表规则 可配置多个表
   t_order:
     actualDataNodes: ds_${0..1}.t_order_${0..1}
     tableStrategy:
       inline:
         shardingColumn: order_id
         algorithmExpression: t_order_${order_id % 2}
     keyGenerator:
       type: SNOWFLAKE
       column: order_id
 bindingTables:
   - t_order
 defaultDatabaseStrategy:
   inline:
     shardingColumn: user_id
     algorithmExpression: ds_${user_id % 2}
 defaultTableStrategy:
   none:

执行语句

use sharding_db;
create table if not exists ds_0.t_order(`order_id` bigint primary key,`user_id` int not null,`status` varchar(50));
insert into t_order(`order_id`,`user_id`,`status`)values(11,1,'jack');

根据插入的id进行运算,11为奇数分配到了t_order_1

读写分离

需要先在Mysql上面配置主从复制,读写分离比较简单,读从库lottery_02,写入主库同步到从库

1、配置规则

schemaName: sharding_db
dataSources:
 master:
   url: jdbc:mysql://127.0.0.1:3306/lottery_01?serverTimezone=Asia/Shanghai&useSSL=false
   username: root
   password: 123456
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
 save:
   url: jdbc:mysql://127.0.0.1:3306/lottery_02?serverTimezone=Asia/Shanghai&useSSL=false
   username: root
   password: 123456
   connectionTimeoutMilliseconds: 30000
   idleTimeoutMilliseconds: 60000
   maxLifetimeMilliseconds: 1800000
   maxPoolSize: 50
masterSlaveRule:
  name: ms_ds
  masterDataSourceName: master
  slaveDataSourceNames:
    - save

2、重新启动

然后查询表t_order_1,这个表同时存在于主从库,最后查到了从库所在的记录行

两者区别

sharding-jdbc是在JDBC层扩展分库分表的,可以理解为增强版的JDBC驱动,支持JDBC协议的数据库的数据库,但目前仅支持Java语言,支持数据分片、读写分离,以 jar 包的形式提供轻量级服务,无proxy代理层,无需额外部署,无其他依赖,适用于Java开发的高性能的轻量级OLTP应用,中小团队

sharding-proxy是屏蔽了底层的分库分表像操作一个数据库一样来进行分库分表,代理了真实数据库,相当于在原有数据库和应用中增加了一层,sharding-proxy是基于 MySQL的,伪装成了MySQL数据库,可以通过DDL/DML等操作来变更数据,对DBA更加友好,适用于OLAP应用以及对分片数据库进行管理和运维的场景

实现原理

ShardingSphere的3个产品的数据分片主要流程是完全一致的

  1. 首先连接到Proxy端口执行一条SQL,通过解析引擎SQL会被解析为抽象语语法树,将里面的每一个单词拆分出来,然后标记可能会改写的位置。
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18

  1. 抽象语法树中的关键字的Token用绿色表示,变量的Token用红色表示,灰色表示需要进一步拆分
    从3.0.x版本开始使用Druid ANTLR作为解析引擎,为了提高效率增加了缓存机制,因此建议采用PreparedStatement预编译的SQL
  2. 路由引擎通过分片规则(取模、哈希、范围、标签、时间等等)路由到真实的库表分片路由
  1. 直接路由:不管SQL是什么样,就要按照规则进行路由,直接指定路由至库表方式分片
  2. 标准路由:当查询是等于、in、between时就是标准路由,路由结果不一定落入唯一的库,一条SQL可能被拆分为多条用于执行的SQL
  3. 笛卡尔积路由:无法根据分片规则计算出SQL应该在哪个数据库、哪个表上执行,那么结果就是把所有分库分表中关联使用到的表交叉查询
  1. 广播路由
  1. 全库表路由:对于不带分片键的DQL和DML,以及DDL等会便利所有库表,一一执行,例如select * from user
  2. 全库路由:对数据库插座都会遍历真实库,例如SET autocommit=0;这种TCL事务控制语句
  3. 全实例路由:对于DCL操作,会在每个数据库实例中执行一遍
  4. 单播路由:仅需要从任意库中的任意真实表中获取数据即可 DESCRIBE t_order;
  5. 阻断路由:用于屏蔽SQL对数据库的操作 USE order_db;,这个命令在真实库中执行
  1. 改写引擎改写SQL语句,把库名表名替换为配置的信息

  2. 执行引擎执行SQL把结果流发送给MySQL服务器,经过MySQL执行后从存储引擎里面把结果集返回出来到Proxy

  3. 归并引擎把接收到的数据归并汇总,然后把结果发送给MySQL客户端

Sharding-jdbc 3.0不支持的sql

  1. 不支持CASE WHEN、HAVING、UNION (ALL),可以拆分查询自己再拼接
  2. 子查询不能出现相同的表
  3. 包含聚合函数的子查询
  4. 同时使用distinct和聚合函数

ShardingSphere扩展点

ShardingAlgorithm扩展点就列出了ShardingSphere默认提供的多种分片策略:

  • InlineShardingAlgorithm:基于⾏表达式的分⽚算法
  • ModShardingAlgorithm:基于取模的分⽚算法
  • HashModShardingAlgorithm:基于哈希取模的分⽚算法
  • FixedIntervalShardingAlgorithm:基于固定时间范围的分⽚算法
  • MutableIntervalShardingAlgorithm:基于可变时间范围的分⽚算法
  • VolumeBasedRangeShardingAlgorithm:基于分⽚容量的范围分⽚算法
  • BoundaryBasedRangeShardingAlgorithm:基于分⽚边界的范围分⽚算法

还有其他分布式主键、分布式ID等等扩展点

分库分表中间件对比

  • Cobar
    阿里 b2b 团队开发和开源的,属于 proxy 层方案,就是介于应用服务器和数据库服务器之间。应用程序通过 JDBC 驱动访问 Cobar 集群,Cobar 根据 SQL 和分库规则对 SQL 做分解,然后分发到 MySQL 集群不同的数据库实例上执行。早些年还可以用,但是最近几年都没更新了,基本没啥人用,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。由于Cobar发起人的离职,Cobar停止维护
  • TDDL
    淘宝团队开发的,属于 client 层方案。支持基本的 crud 语法和读写分离,但不支持 join、多表查询等语法。目前使用的也不多,因为还依赖淘宝的 diamond 配置管理系统。
  • Atlas
    是360团队基于mysql proxy改写,功能还需完善,高并发下不稳定
  • Sharding-jdbc
    当当开源的,属于 client 层方案,目前已经更名为 ShardingSphere(后文所提到的 Sharding-jdbc,等同于 ShardingSphere)。确实之前用的还比较多一些,因为 SQL 语法支持也比较多,没有太多限制,而且截至 2019.4,已经推出到了 4.0.0-RC1 版本,支持分库分表、读写分离、分布式 id 生成、柔性事务(最大努力送达型事务、TCC 事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从 2017 年一直到现在,是有不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也可以选择的方案。
  • Mycat
    基于 Cobar 改造的,解决了cobar存在的问题,并且加入了许多新的功能在其中。青出于蓝而胜于蓝,属于 proxy 层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于 Sharding jdbc 来说,年轻一些,经历的锤炼少一些。

Sharing-jdbc不用部署,直接使用jar包,相对维护起来比较简单,运维成本低

Mycat属于代理Proxy,需要部署运维,它是一个中间件

建议中小型公司选用 Sharding-jdbc,client 层方案轻便,而且维护成本低,不需要额外增派人手,而且中小型公司系统复杂度会低一些,项目也没那么多;但是中大型公司最好还是选用 Mycat 这类 proxy 层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,那么最好是专门弄个人来研究和维护 Mycat,然后大量项目直接透明使用即可

分布分表应用和问题

1、在数据库设计的时候就考虑垂直分库和分表

2、数据库数据越来越多不要考虑水平切分,先考虑读写分离,使用索引等等。如果解决不了在使用水平分表

带来的问题:

  • 跨分片的事务一致性难以保证
  • 跨库的join关联查询性能较差
  • 数据多次扩展难度和维护量极大
  • 查询问题表分布在不同的库里面
  • 分页查询不方便

解决方案:

  1. 跨分片的事务一致性难以保证
  • 拆分成多个小事务,来进行总控制
  • 使用分布式事务,性能代价高(推荐)
  1. join操作
  1. 数据分布在不同的表:分两次查询再合并,先查关联id再根据关联id去另一个表查数据(推荐)
  2. 全局数据:这样的数据比较少修改,很多模块都会依赖这个表,这样可以在每个数据库保存一份,避免跨库查询
  3. 字段冗余:可能需要的数据字段在详细表中,可以将字段放过来,避免join查询
  4. Mycat支持跨库join
  1. count操作
    先在不同库中把数据取出来,最后再统计
  2. 分页操作
    1、数据拼装:先在不同库中把数据取出来,最后再合并分页,如果数据量太大很消耗系统资源,性能也很差
    2、禁止跳页:降低技术方案
    3、数据库均衡:如果数据差不多均衡的话,各个库各取一半数据,优点是不需要再进行内存排序,但是精度可能会丢失一些
  3. 数据多次扩展难度和维护量极大
  4. 查询问题
  1. 直接查询:每个数据库执行一遍语句,性能差
  2. 模糊查询:数据拼装
  3. 使用关联表/关联字段:具体表分布在哪个库
  4. MyCat多线程查询:类似第一种方式
  5. 异构索引:额外建立一个索引表记录分片键和非分片字段的对应关系,例如通过xx字段找到订单id,然后根据订单id找到对应的库(方法可以,但没法通用范围,状态等等不好查)
  6. 实时数仓:通过中间件监听数据库binlog日志,实时收集数据
  1. 分表后使用非分片字段查询问题(根据任意一个字段查询数据,如何找到所在表)
    根据订单ID进行分库,如果需要删除前一天的订单记录,那么需要在每个库中执行一遍sql,没法确定哪个库执行哪个库不执行
    解决办法:冗余字段:因为是根据订单id进行路由的,那么几个路由的键都是固定的,比如路由到3个库,那么0、1、2分别代表这三个库的索引,在表里面记录下这个字段,就可以直接找到这个库进行删除。
  2. 主键ID问题(为什么不使用自增或者UUID)
  1. 使用自增可能会出现ID重复的问题
  2. 使用UUID 缺点:太长不方便排序
  3. 雪花算法:(0+41位时间戳+10位工作机器id+12位序列号)传给前端的时候用String,使用Long的话前端js会溢出。缺点:时间戳依赖于机器时钟。如果机器时间回调,还是可能会有冲突
  4. 使用redis生成分布式主键
    使用redis生成数据库主键自增_一渣程序猿的博客-CSDN博客_redis生成自增主键
  1. 数据扩缩容
  1. 扩容的话:一般是因为数据量太多磁盘快满了,原有两台机器,每台机器2个库,每个库4个表,总共个16表,增加服务器2个服务器,每台服务器增加两个库,调整为每个服务器的一个库,每个库里面还是固定的2张表
    分片id 取模 8/=库
    分片id /8 ,再取模8 = 表
  1. 数据迁移(如何在旧数据上做分库分表)
  1. 半夜系统停机,停止写入数据然后使用中间件写入(废人)
  2. 系统不停机,使用双写方案,数据同时写入新库新表和旧表,等于两份数据。再用工具去去读老库的数据到新库中,可以根据主键id或者修改时间区分数据。可能会造成代码入侵,可以监听binlog日志,最后再校验数据是否准确,先校验数量,再使用随机采样法抽取几十条数据合并,比较是否相等通过Base64加密对比
相关实践学习
自建数据库迁移到云数据库
本场景将引导您将网站的自建数据库平滑迁移至云数据库RDS。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
运维 安全 Cloud Native
国产Linux:OpenEuler能否完美替代CentOS系统?
本文讨论了OpenEuler系统作为替代CentOS的一个有潜力的选择。OpenEuler系统是一种基于开源技术和社区支持的Linux发行版,具有许多优势,如安全性、高度可定制性、强大的社区支持、容器和云原生生态系统集成以及持续更新等。与CentOS相比,OpenEuler系统提供更多的灵活性和可定制性,适用于各种用途和工作负载。但在选择OpenEuler系统时,用户需要进行仔细评估并考虑其适用性和可行性。
|
关系型数据库 MySQL Java
Sharding-Proxy的基本功能使用
Sharding-Proxy是一个分布式数据库中间件,定位为透明化的数据库代理端。作为开发人员可以完全把它当成数据库,而它具体的分片规则在Sharding-Proxy中配置。
3594 0
Sharding-Proxy的基本功能使用
|
SQL 关系型数据库 MySQL
ShardingSphere-Sharding-Proxy(安装和分表配置)| 学习笔记
快速学习ShardingSphere-Sharding-Proxy(安装和分表配置)。
ShardingSphere-Sharding-Proxy(安装和分表配置)| 学习笔记
|
9月前
|
自然语言处理 DataWorks 数据挖掘
DataWorks接入Qwen3-Coder!数据开发再提速!
阿里云DataWorks平台正式接入Qwen3-Coder模型,用户通过DataWorks Copilot智能助手,可实现自然语言交互完成代码生成、续写、优化等操作,显著提升数据开发与分析效率。同时支持Qwen-Code和Claude Code命令行Agent安装,助力Notebook智能高效落地。
|
SQL 存储 Oracle
大厂面试高频:聊下分库分表与读写分离的实现原理
本文详解了分库分表和读写分离的原理与实现,帮助解决大数据量下的性能瓶颈问题,大厂面试高频,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:聊下分库分表与读写分离的实现原理
|
算法 关系型数据库 MySQL
十五张图带你快速入门 shardingsphere-proxy
Apache ShardingSphere 是一款分布式的数据库生态系统,它包含两大产品: - ShardingSphere-Proxy - ShardingSphere-JDBC 很多同学对于 ShardingSphere-JDBC 已经能非常熟悉的使用了,但关于网上关于 ShardingSphere-Proxy 5.5 的使用教程却非常少。
十五张图带你快速入门 shardingsphere-proxy
|
网络安全
ceph的mgr组件模块dashboard图形化管理ceph集群
关于如何通过Ceph的mgr组件模块dashboard来图形化管理Ceph集群的教程,包括基于HTTP和HTTPS的配置步骤。
1148 3
|
Ubuntu 数据安全/隐私保护
Ubuntu下安装clickhouse
1、创建/etc/apt/sources.list.d/clickhouse.list文件, 2、在clickhouse.list文件里写入deb http://repo.yandex.ru /clickhouse/deb/stable/ main/ 3、一定要在clickhouse.
3751 0
|
SQL cobar 算法
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
7035 6
SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
|
Shell Linux 网络安全
linux shell 终端中文乱码(转)
方法一:修改/etc/sysconfig/i18n 文件把里面的LANG="en_US"改成 GB2312就可以了要重启一下机器不用重启的方法,直接# LANG="GB2312"然后就可以了修改 i18n 只是为了重启有效 方法二:#vi ~/.
9090 0