114 Star 686 Fork 132

automvc / bee

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
2.0-sharding.md 10.83 KB
一键复制 编辑 原始数据 按行查看 历史
automvc 提交于 2022-10-10 22:09 . update

读写分离,分库,分表,分库分表,

在读写分离的情况下,应用需要对读sql/写sql进行区分,读sql走从库,写sql走主库,并考虑主从同步延迟、高可用等一系列问题。 在分库分表的情况下,应用需要能对sql进行解析、改写、路由、结果集合并等一些操作,以及分布式事务、分布式id生成器等。路由至单节点的SQL,则无需优化改写。

为什么要分表,分库? 一旦业务表中的数据量大了,从维护和性能角度来看,无论是任何的 CRUD 操作,对于数据库而言都是一件极其耗费资源的事情。即便设置了索引, 仍然无法掩盖因为数据量过大从而导致的数据库性能下降的事实 ,这个时候就该对数据库进行 水平分区 (sharding,即分库分表 ),将原本一张表维护的海量数据分配给 N 个子表进行存储和维护。 延缓分表分库? 将业务表、订单表中旧的历史数据移到历史表。其实这就是分表的雏形。

类型: 1)只分表: (可以只有一个数据源) (V1.8已实现) 同库的分表(只分表不分库) 按月份,按单位建表放数据。 将db库中的user表拆分为2个分表,user_0和user_1,这两个表还位于同一个库中。 2)只分库 (V1.8已实现) 将db库拆分为db_0和db_1两个库,同时在db_0和db_1库中各自新建一个user表,db_0.user表和db_1.user表中各自只存原来的db.user表中的部分数据。 (因各库的表,只存原来的一部分数据,涉及到字段分片) 而以下这种分库,却仍有可能只用单数据源。 只分库不分表,但原单点库中的表各自移到不同的库中 (各分库有原库中的部分表,典型的:将不同业务的表拆分到不同的库中) 现在流行的微服务就是按业务打包成一个个服务。或一个服务,只用到一个库,还是可以用单数据源。

3)复制型分库 (V1.8已实现) 复制型分库(读写分离,每个库的表都一样) 每个库中的表数据是一样的(因同步原因,可能最终一致会有延迟)。

4)既分库也分表 (计划在V2.0) 将db库拆分为db_0和db_1两个库,db_0中包含user_0、user_1两个分表,db_1中包含user_2、user_3两个分表。

目标: 支持数据库分库分表的ORM中间件的作用,是让开发人员可以像操作单库单表那样去操作数据库,屏蔽底层复杂的实现。

1.读写分离 (V1.8已实现) 读写分离,每个库都一样(表都一样,只是部署在不同的节点,如ip不一样)。 从应用的角度来说,需要对读(select、show、explain等)、写(insert、update、delete等)操作进行区分。如果是写操作,就走主库,主库会将数据同步给从库;之后有读操作,就走从库, 从多个从库中选择一个,查询数据。 1)写操作走主库,从操作走多个读库; 2)如果一个事务中同时包含了读请求(如select)和写请求(如insert),则统一走主库(避免分布式事务问题)。 很强的一致性场景时,可以主动要求,进行从库的同步吗? 3)主从同步,由DB本身负责,如Mysql proxy. 应用需要考虑主从同步延迟。

解决方法: 通过判断操作类型,切换数据源完成。不涉及sql重写,改写. 数据源,可以设置,有更新时能改动,以便能感知更新(主库切换,从库增减等)。 一个事务中同时包含了读请求(如select)和写请求(如insert),则统一走主库。比较容易实现,在开启事务时,路由到写库的conn即可。 同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性; 怎么知道线程线程结束? 什么时候才能将连接放回连接池。

读写分离优点 避免单点故障。 负载均衡,读能力水平扩展。通过配置多个从库节点,可以有效的避免过大的访问量对单个库造成的压力。

在读写分离的情况下,应用需要对读sql/写sql进行区分,读sql走从库,写sql走主库,并考虑主从同步延迟、高可用等一系列问题。

2.同库的分表 (V1.8已实现) 按日期分成多个表,按编号分成多个表 选写分表键(用于找到相应表的键),如时间id. 1)事务暂时只支持一个库的(暂时不支持多库分表,避免分布式事务)。 2)javabean与表的映射 3)sql重写,改写 update修改分表字段的值时,只会修改值,不会根据修改后的值再对数据进行迁移.这样会产生问题。除非sql不改写,每个库都运行一样的sql,再将结果合并。 分表时,表名是不一样的。 同时多个表更新,如何回滚? 打印的sql,是实际执行的sql,连DataSource的名称也打印出来。跟Sharding不一样。DBA,开发人员看到user001就知道是user表,没必要对他们隐藏这些细节. 路由至单节点的SQL,则无需优化改写。 因此先选定DS,再确定下一步的操作。 4)

  1. 总规则: 核心概念: **分片路由分为字段的分片和表的分片。 分片算法 提供对 SQL 语句中的 =, >, <, >=, <=和 BETWEEN AND ,IN 的分片操作支持 广播表:配置表、参数表等,每个库都可以放一份。

可以选择分片,也可以不用它。 有些表的编号,是通过分片字段计算来的。如user0中的0可以通过某字段求余得来。 设置默认DS,路由找不到DS时,使用默认那个。 ***DS如何根据规则路由;表如何根据规则解析成正确的表,从而生成正确的sql;根据分片键确定是否要生成多条sql.

可能在生成sql时,就按库或表,分好。

中间件检测到你的sql脚本是插入、更新、删除的语句,自动选择主数据源;如果是查询语句,则随机选择一个读数据源;开启了事务会根据事务选择数据源。 因此,数据源,还有类型属性,同一类型的从库是一样的,缓存共用。

强制分片路由: (参考设计:仅在当前线程内生效)

用户可以指定使用的具体 ds 和 table,而无需使用分片值通过路由算法计算。在 Bee 中,可以使用HintManager指定.

4.高可用: 配置信息动态生效 在注册中心上修改、删除、新增相关配置,会动态推送到生产环境并立即生效。 参考:永久且同步配置。

5.分库不分表 (V1.8已实现) 读写分离算是一种典型的分库不分表。因为每个库的表是一样. 一般的有如,将不同业务的表拆分到不同的库中,可根据表来路由。

6.分库分表 暂不支持。
(计划在V2.0) 为什么? 原因如下: 跨库事务也是分布式的数据库集群要面对的棘手事情。 合理采用分表,可以在降低单表数据量的情况下,尽量使用本地事务,善于使用同库不同表可有效避免分布式事务带来的麻烦。 在不能避免跨库事务的场景,有些业务仍然需要保持事务的一致性。 而基于XA的分布式事务由于在并发度高的场景中性能无法满足需要,并未被互联网巨头大规模使用,他们大多采用 最终一致性的柔性事务代替强一致事务。

从应用的角度来说,需要对读(select、show、explain等)、写(insert、update、delete等)操作进行区分。如果是写操作,就走主库,主库会将数据同步给从库;之后有读操作,就走从库, 从多个从库中选择一个,查询数据。 事务问题。如果一个事务中同时包含了读请求(如select)和写请求(如insert),如果读请求走从库,写请求走主库,由于跨了多个库,那么jdbc本地事务已经无法控制,属于分布式事务的范畴。而分布式事务非常复杂且效率较低。因此对于读写分离, 目前主流的做法是,事务中的所有sql统一都走主库,由于只涉及到一个库,jdbc本地事务就可以搞定。

补列 排序分页,要改写sql

正确性改写 标识符改写 补列 分页修正 批量拆分 优化改写 单节点优化 流式归并优化

用Suid的好处,

mysql: 分页方案优化 由于LIMIT并不能通过索引查询数据,因此如果可以保证ID的连续性,通过ID进行分页是比较好的解决方案:

SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id 或通过记录上次查询结果的最后一条记录的ID进行下一页的查询: SELECT * FROM t_order WHERE id > 100000 LIMIT 10 sql输出,提示是经过优化的sql.用不带分页的部分sql为key,缓存上一次查询的id.

4.3 分库分表的Join 一般情况下,分库分表后,就不能再和单表一样进行Join了,目前zebra支持以下两种情况的Join。

4.3.2 关联表 (主表与从表)

关联表指存在主外键关系的主表与从表,它们一般是一对多的关系,按照一定的 DB 设计原则将数据存放到两张表中。如:orders,orders_item; users,users_item; 它们一般都是有外键关系关系(未必使用外键约束)。因此关联表的分片规则应使用一样的,同一个查询语句中,主从表应该有一样的下标(后缀)。 4.3.1 广播表 指所有的分片数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。 分片中间件,应该支持更新广播表时,同一表的所有广播表都更新。

分库分表优点 分库的好处: 降低单台机器的负载压力,提升写入性能

分表的好处: 提高数据操作的效率。举个例子说明,比如user表中现在有4000w条数据,此时我们需要在这个表中增加(insert)一条新的数据,insert完毕后,数据库会针对这张表重新建立索引,4000w行数据建立索引的系统开销还是不容忽视的。 但是反过来,假如我们将这个表分成4 个table呢,从user_0一直到user_3,4000w行数据平均下来,每个子表里边就只有1000W行数据,这时候我们向一张 只有1000W行数据的table中insert数据后建立索引的时间就会下降,从而提高DB的运行时效率, 提高了DB的并发量。除了提高写的效率,更重要的是提高读的效率,提高查询的性能。当然分表的好处还不止这些,还有诸如写操作的锁操作等,都会带来很多显然的好处。

注意:无论选择什么拆分键,采用何种拆分策略,都要注意拆分值是否存在热点的问题,尽量规避热点数据来选择拆分键。 注意:不一定需要拿数据库主键当做分表键,也可以拿其他业务值当分表键。拿主键当分表键的好处是可以散列均衡,减少热点问题。

Java
1
https://gitee.com/automvc/bee.git
git@gitee.com:automvc/bee.git
automvc
bee
bee
master

搜索帮助