数据库-垂直水平分库
当一张表的数据达到几千万时,查询一次所花的时间会变长。业界公认MySQL单表容量在 1千万 以下是最佳状态,因为这时它的BTREE索引树高在3~5之间。
数据切分可以分为:垂直切分
和水平切分
。
一、垂直切分
垂直切分又可以分为: 垂直分库
和垂直分表
。
1、垂直分库
概念
就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,
每个微服务使用单独的一个数据库。
如图:
说明
一开始我们是单体服务,所以只有一个数据库,所有的表都在这个库里。
后来因为业务需求,单体服务变成微服务治理。所以将之前的一个商品库,拆分成多个数据库。每个微服务对于一个数据库。
2、垂直分表
概念
把一个表的多个字段分别拆成多个表,一般按字段的冷热拆分,热字段一个表,冷字段一个表。从而提升了数据库性能。
如图:
说明
一开始商品表中包含商品的所有字段,但是我们发现:
1.商品详情和商品属性字段较长
。2.商品列表的时候我们是不需要显示商品详情和商品属性信息,只有在点进商品商品的时候才会展示商品详情信息
。
所以可以考虑把商品详情和商品属性单独切分一张表,提高查询效率。
3、垂直切分优缺点
优点
- 解决业务系统层面的耦合,业务清晰
- 与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
- 高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈
缺点
- 分库后无法Join,只能通过接口聚合方式解决,提升了开发的复杂度
- 分库后分布式事务处理复杂
- 依然存在单表数据量过大的问题(需要水平切分)
二、水平切分
当一个应用难以再细粒度的垂直切分或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分也可以分为:水平分库
和水平分表
。
1、水平分库
水平分库的原因
上面虽然已经把商品库分成3个库,但是随着业务的增加一个订单库也出现QPS过高,数据库响应速度来不及,一般mysql单机也就1000左右的QPS,如果超过1000就要考虑分库。
如图
2、水平分表
概念
一般我们一张表的数据不要超过1千万,如果表数据超过1千万,并且还在不断增加数据,那就可以考虑分表。
如图
3、水平切分优缺点
优点
- 不存在单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力
- 应用端改造较小,不需要拆分业务模块
缺点
- 跨分片的事务一致性难以保证
- 跨库的Join关联查询性能较差
- 数据多次扩展难度和维护量极大
三、数据分片规则
我们我们考虑去水平切分表,将一张表水平切分成多张表,这就涉及到数据分片的规则,比较常见的有:Hash取模分表
、数值Range分表
、一致性Hash算法分表
。
1、Hash取模分表
概念
一般采用Hash取模的切分方式,例如:假设按goods_id分4张表。(goods_id%4 取整确定表)
优点
- 数据分片相对比较均匀,不容易出现热点和并发访问的瓶颈。
缺点
- 后期分片集群扩容时,需要迁移旧的数据很难。
- 容易面临跨分片查询的复杂问题。比如上例中,如果频繁用到的查询条件中不带goods_id时,将会导致无法定位数据库,从而需要同时向4个库发起查询,
再在内存中合并数据,取最小集返回给应用,分库反而成为拖累。
2、数值Range分表
概念
按照时间区间或ID区间来切分。例如:将goods_id为11000的记录分到第一个表,10012000的分到第二个表,以此类推。
如图
优点
- 单表大小可控
- 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
- 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。
缺点
- 热点数据成为性能瓶颈。
例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询
3、一致性Hash算法
一致性Hash算法能很好的解决因为Hash取模而产生的分片集群扩容时,需要迁移旧的数据的难题
。至于具体原理这里就不详细说,
可以参考一篇博客:一致性哈希算法(分库分表,负载均衡等)
四、分库分表带来的问题
任何事情都有两面性,分库分表也不例外,如果采用分库分表,会引入新的的问题
1、分布式事务问题
使用分布式事务中间件解决,具体是通过最终一致性还是强一致性分布式事务,看业务需求,这里就不多说。
2、跨节点关联查询 Join 问题
切分之前,我们可以通过Join来完成。而切分之后,数据可能分布在不同的节点上,此时Join带来的问题就比较麻烦了,考虑到性能,尽量避免使用Join查询。
解决这个问题的一些方法:
全局表
全局表,也可看做是 "数据字典表",就是系统中所有模块都可能依赖的一些表,为了避免跨库Join查询,可以将 这类表在每个数据库中都保存一份。这些数据通常
很少会进行修改,所以也不担心一致性的问题。
字段冗余
利用空间换时间,为了性能而避免join查询。例:订单表保存userId时候,也将userName冗余保存一份,这样查询订单详情时就不需要再去查询"买家user表"了。
数据组装
在系统层面,分两次查询。第一次查询的结果集中找出关联数据id,然后根据id发起第二次请求得到关联数据。最后将获得到的数据进行字段拼装。
3、跨节点分页、排序、函数问题
跨节点多库进行查询时,会出现Limit分页、Order by排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片;
当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户。
4、全局主键避重问题
如果都用主键自增
肯定不合理,如果用UUID
那么无法做到根据主键排序,所以我们可以考虑通过雪花ID
来作为数据库的主键,
有关雪花ID可以参考我之前写的博客:静态内部类单例模式实现雪花算法
5、数据迁移问题
采用双写的方式
,修改代码,所有涉及到分库分表的表的增、删、改的代码,都要对新库进行增删改。同时,再有一个数据抽取服务,不断地从老库抽数据,往新库写,
边写边按时间比较数据是不是最新的。
---------------------------------------
数据库很容易成为应用系统的瓶颈。单机数据库的资源和处理能力有限,在高并发的分布式系统中,可采用分库分表突破单机局限。本文总结了分库分表的相关概念、全局ID的生成策略、分片策略、平滑扩容方案、以及流行的方案。
1 分库分表概述
在业务量不大时,单库单表即可支撑。
当数据量过大存储不下、或者并发量过大负荷不起时,就要考虑分库分表。
1.1 分库分表相关术语
-
读写分离: 不同的数据库,同步相同的数据,分别只负责数据的读和写;
-
分区: 指定分区列表达式,把记录拆分到不同的区域中(必须是同一服务器,可以是不同硬盘),应用看来还是同一张表,没有变化;
-
分库:一个系统的多张数据表,存储到多个数据库实例中;
-
分表: 对于一张多行(记录)多列(字段)的二维数据表,又分两种情形:
(1) 垂直分表: 竖向切分,不同分表存储不同的字段,可以把不常用或者大容量、或者不同业务的字段拆分出去;
(2) 水平分表(最复杂): 横向切分,按照特定分片算法,不同分表存储不同的记录。
1.2 真的要采用分库分表?
需要注意的是,分库分表会为数据库维护和业务逻辑带来一系列复杂性和性能损耗,除非预估的业务量大到万不得已,切莫过度设计、过早优化
。
规划期内的数据量和性能问题,尝试能否用下列方式解决:
-
当前数据量:如果没有达到几百万,通常无需分库分表;
-
数据量问题:增加磁盘、增加分库(不同的业务功能表,整表拆分至不同的数据库);
-
性能问题:升级CPU/内存、读写分离、优化数据库系统配置、优化数据表/索引、优化 SQL、分区、数据表的垂直切分;
-
如果仍未能奏效,才考虑最复杂的方案:数据表的水平切分。
2 全局ID生成策略
2.1 自动增长列
优点:数据库自带功能,有序,性能佳。
缺点:单库单表无妨,分库分表时如果没有规划,ID可能重复。解决方案:
2.1.1 设置自增偏移和步长
-
### 假设总共有 10 个分表
-
### 级别可选: SESSION(会话级), GLOBAL(全局)
-
SET @@SESSION.auto_increment_offset = 1; ### 起始值, 分别取值为 1~10
-
SET @@SESSION.auto_increment_increment = 10; ### 步长增量
如果采用该方案,在扩容时需要迁移已有数据至新的所属分片。
2.1.2 全局ID映射表
在全局 Redis 中为每张数据表创建一个 ID 的键,记录该表当前最大 ID;
每次申请 ID 时,都自增 1 并返回给应用;
Redis 要定期持久至全局数据库。
2.2 UUID(128位)
在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成UUID的API。
UUID 由4个连字号(-)将32个字节长的字符串分隔后生成的字符串,总共36个字节长。形如:550e8400-e29b-41d4-a716-446655440000。
UUID 的计算因子包括:以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
UUID 是个标准,其实现有几种,最常用的是微软的 GUID(Globals Unique Identifiers)。
优点:简单,全球唯一;
缺点:存储和传输空间大,无序,性能欠佳。
2.3 COMB(组合)
参考资料:The Cost of GUIDs as Primary Keys
组合 GUID(10字节) 和时间(6字节),达到有序的效果,提高索引性能。
2.4 Snowflake(雪花) 算法
参考资料:twitter/snowflake,Snowflake 算法详解
Snowflake 是 Twitter 开源的分布式 ID 生成算法,其结果为 long(64bit) 的数值。
其特性是各节点无需协调、按时间大致有序、且整个集群各节点单不重复。
该数值的默认组成如下(符号位之外的三部分允许个性化调整):
-
1bit: 符号位,总是 0(为了保证数值是正数)。
-
41bit: 毫秒数(可用 69 年);
-
10bit: 节点ID(5bit数据中心 + 5bit节点ID,支持 32 * 32 = 1024 个节点)
-
12bit: 流水号(每个节点每毫秒内支持 4096 个 ID,相当于 409万的 QPS,相同时间内如 ID 遇翻转,则等待至下一毫秒)
3 分片策略
3.1 连续分片
根据特定字段(比如用户ID、订单时间)的范围,值在该区间的,划分到特定节点。
优点:集群扩容后,指定新的范围落在新节点即可,无需进行数据迁移。
缺点:如果按时间划分,数据热点分布不均(历史数冷当前数据热),导致节点负荷不均。
3.3 ID取模分片
缺点:扩容后需要迁移数据。
3.2 一致性Hash算法
优点:扩容后无需迁移数据。
3.4 Snowflake 分片
优点:扩容后无需迁移数据。
4 分库分表引入的问题
4.1 分布式事务
参见 分布式事务的解决方案
由于两阶段/三阶段提交对性能损耗大,可改用事务补偿机制。
4.2 跨节点 JOIN
对于单库 JOIN,MySQL 原生就支持;
对于多库,出于性能考虑,不建议使用 MySQL 自带的 JOIN,可以用以下方案避免跨节点 JOIN:
-
全局表: 一些稳定的共用数据表,在各个数据库中都保存一份;
-
字段冗余: 一些常用的共用字段,在各个数据表中都保存一份;
-
应用组装:应用获取数据后再组装。
另外,某个 ID 的用户信息在哪个节点,他的关联数据(比如订单)也在哪个节点,可以避免分布式查询。
4.3 跨节点聚合
只能在应用程序端完成。
但对于分页查询,每次大量聚合后再分页,性能欠佳。
4.4 节点扩容
节点扩容后,新的分片规则导致数据所属分片有变,因而需要迁移数据。
5 节点扩容方案
相关资料: 数据库秒级平滑扩容架构方案
5.1 常规方案
如果增加的节点数和扩容操作没有规划,那么绝大部分数据所属的分片都有变化,需要在分片间迁移:
-
预估迁移耗时,发布停服公告;
-
停服(用户无法使用服务),使用事先准备的迁移脚本,进行数据迁移;
-
修改为新的分片规则;
-
启动服务器。
5.2 免迁移扩容
采用双倍扩容策略,避免数据迁移。扩容前每个节点的数据,有一半要迁移至一个新增节点中,对应关系比较简单。
具体操作如下(假设已有 2 个节点 A/B,要双倍扩容至 A/A2/B/B2 这 4 个节点):
-
无需停止应用服务器;
-
新增两个数据库 A2/B2 作为从库,设置主从同步关系为:A=>A2、B=>B2,直至主从数据同步完毕(早期数据可手工同步);
-
调整分片规则并使之生效:
原ID%2=0 => A
改为ID%4=0 => A, ID%4=2 => A2
;
原ID%2=1 => B
改为ID%4=1 => B, ID%4=3 => B2
。 -
解除数据库实例的主从同步关系,并使之生效;
-
此时,四个节点的数据都已完整,只是有冗余(多存了和自己配对的节点的那部分数据),择机清除即可(过后随时进行,不影响业务)。
6 分库分表方案
6.1 代理层方式
部署一台代理服务器伪装成 MySQL 服务器,代理服务器负责与真实 MySQL 节点的对接,应用程序只和代理服务器对接。对应用程序是透明的。
比如 MyCAT,官网,源码,参考文档:MyCAT+MySQL 读写分离部署
MyCAT 后端可以支持 MySQL, SQL Server, Oracle, DB2, PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。
MyCAT 不仅仅可以用作读写分离,以及分表分库、容灾管理,而且可以用于多租户应用开发、云平台基础设施,让你的架构具备很强的适应性和灵活性。
6.2 应用层方式
处于业务层和 JDBC 层中间,是以 JAR 包方式提供给应用调用,对代码有侵入性。主要方案有:
(1)淘宝网的 TDDL: 已于 2012 年关闭了维护通道,建议不要使用。
(2)当当网的 Sharding-JDBC: 仍在活跃维护中:
是当当应用框架 ddframe 中,从关系型数据库模块 dd-rdb 中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问,实现了 Snowflake 分片算法;
Sharding-JDBC定位为轻量Java框架,使用客户端直连数据库,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。
Sharding-JDBC分片策略灵活,可支持等号、between、in等多维度分片,也可支持多分片键。
SQL解析功能完善,支持聚合、分组、排序、limit、or等查询,并支持Binding Table以及笛卡尔积表查询。
Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零:
-
可适用于任何基于Java的ORM框架,如JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
-
可基于任何第三方的数据库连接池,如DBCP、C3P0、 BoneCP、Druid等。
-
理论上可支持任意实现JDBC规范的数据库。虽然目前仅支持MySQL,但已有支持Oracle、SQLServer等数据库的计划。
数据库水平分库扩展
为了增加db的并发能力,常见的方案就是对数据进行sharding,也就是常说的分库分表,这个需要在初期对数据规划有一个预期,从而预先分配出足够的库来处理。
比如目前规划了3个数据库,基于uid进行取余分片,那么每个库上的划分规则如下:
我们可以看到,数据可以均衡的分配到3个数据库里面。
但是,如果后续业务发展的速度很快,用户量数据大量上升,当前容量不足以支撑,应该怎么办?
需要对数据库进行水平扩容,再增加新库来分解。新库加入之后,原先sharding到3个库的数据,就可以sharding到四个库里面了:
不过此时由于分片规则进行了变化(uid%3 变为 uid%4),大部分的数据,无法命中在原有的数据库上了,需要重新分配,大量数据需要迁移。
比如之前uid1通过uid1%3 分配在A库上,新加入库D之后,算法改为uid1%4 了,此时有可能就分配在B库上面了。如果你有看到之前《一致性哈希的原理与实践》,就会发现新增一个节点,大概会有90%的数据需要迁移,这个对DB同学的压力还是蛮大的,那么如何应对?
一般有以下几种方式:
停服迁移
停服迁移是最常见的一种方案了,一般如下流程:
-
预估停服时间,发布停服公告;
-
停服,通过事先做好的数据迁移工具,按照新的分片规则,进行迁移;
-
修改分片规则;
-
启动服务。
我们看到这种方式比较安全,停服之后没有数据写入,能够保证迁移工作的正常进行,没有一致性的问题。唯一的问题,就是停服了和时间压力了。
缺点:
-
停服,伤害用户体验,同时也降低了服务器的可用性;
-
必须在制定时间内完成迁移,如果失败,需要择日再次进行。同时增加了开发人员的压力,容易发生大的事故;
-
数据量的巨大的时候,迁移需要大量时间。
那有没有其他方式来改进一下,我们看下以下两种方案:
升级从库
线上数据库,我们为了保持其高可用,一般都会每台主库配一台从库,读写在主库,然后主从同步到从库。如下,A,B是主库,A0和B0是从库。
此时,当需要扩容的时候,我们把A0和B0升级为新的主库节点,如此由2个分库变为4个分库。同时在上层的分片配置,做好映射,规则如下:
uid%4=0和uid%4=2的分别指向A和A0,也就是之前指向uid%2=0的数据,分裂为uid%4=0和uid%4=2
uid%4=1和uid%4=3的指向B和B0,也就是之前指向uid%2=1的数据,分裂为uid%4=1和uid%4=3
因为A和A0库的数据相同,B和B0数据相同,所以此时无需做数据迁移。只需要变更一下分片配置即可,通过配置中心更新,无需重启。
由于之前uid%2的数据分配在2个库里面,此时分散到4个库中,由于老数据还存在(uid%4=0,还有一半uid%4=2的数据),所以需要对冗余数据做一次清理。
而这个清理,不会影响线上数据的一致性,可是随时随地进行。
处理完成以后,为保证高可用,以及下一步扩容需求。可以为现有的主库再次分配一个从库。
总结一下此方案步骤如下:
-
修改分片配置,做好新库和老库的映射。
-
同步配置,从库升级为主库
-
解除主从关系
-
冗余数据清理
-
为新的数据节点搭建新的从库
双写迁移
双写的方案,更多的是针对线上数据库迁移来用的,当然了,对于分库的扩展来说也是要迁移数据的,因此,也可以来协助分库扩容的问题。
原理和上述相同,做分裂扩容,只是数据的同步方式不同了。
一、增加新库写链接
双写的核心原理,就是对需要扩容的数据库上,增加新库,并对现有的分片上增加写链接,同时写两份数据。
因为新库的数据为空,所以数据的CRUD对其没有影响,在上层的逻辑层,还是以老库的数据为主。
二、新老库数据迁移
通过工具,把老库的数据迁移到新库里面,此时可以选择同步分裂后的数据(1/2)来同步,也可以全同步,一般建议全同步,最终做数据校检的时候好处理。
三、数据校检
按照理想环境情况下,数据迁移之后,因为是双写操作,所以两边的数据是一致的,特别是insert和update,一致性情况很高。但真实环境中会有网络延迟等情况,对于delete情况并不是很理想,比如:
A库删除数据a的时候,数据a正在迁移,还没有写入到C库中,此时C库的删除操作已经执行了,C库会多出一条数据。
此时就需要做好数据校检了,数据校检可以多做几遍,直到数据几乎一致,尽量以旧库的数据为准。
四、分片配置修改
数据同步完毕,就可以把新库的分片映射重新处理了,还是按照老库分裂的方式来进行:
uid%2=0,变为uid%4=0和uid%4=2
uid%2=1,变为uid%4=1和uid%4=3
五、冗余数据清理
最后,还是需要对冗余数据做一次清理。
一、为什么要分库分表
如果一个网站业务快速发展,那这个网站流量也会增加,数据的压力也会随之而来,比如电商系统来说双十一大促对订单数据压力很大,Tps十几万并发量,如果传统的架构(一主多从),主库容量肯定无法满足这么高的Tps,业务越来越大,单表数据超出了数据库支持的容量,持久化磁盘IO,传统的数据库性能瓶颈,产品经理业务·必须做,改变程序,数据库刀子切分优化。数据库连接数不够需要分库,表的数据量大,优化后查询性能还是很低,需要分。
二、什么是分库分表
- 分库分表方案是对关系型数据库数据存储和访问机制的一种补充。
- 分库:将一个库的数据拆分到多个相同的库中,访问的时候访问一个库
- 分表:把一个表的数据放到多个表中,操作对应的某个表就行
三、分库分表的几种方式
1.垂直拆分
(1) 数据库垂直拆分
根据业务拆分,如图,电商系统,拆分成订单库,会员库,商品库
(2)表垂直拆分
根据业务去拆分表,如图,把user表拆分成user_base表和user_info表,use_base负责存储登录,user_info负责存储基本用户信息
垂直拆分特点:
- 每个库(表)的结构都不一样
- 每个库(表)的数据至少一列一样
- 每个库(表)的并集是全量数据
垂直拆分优缺点
优点:
- 拆分后业务清晰(专库专用按业务拆分)
- 数据维护简单,按业务不同,业务放到不同机器上
缺点:
- 如果单表的数据量,写读压力大
- 受某种业务决定,或者被限制,也就是说一个业务往往会影响到数据库的瓶颈(性能问题,如双十一抢购)
- 部分业务无法关联join,只能通过java程序接口去调用,提高了开发复杂度
2. 水平拆分
(1) 数据库水平拆分
如图,按会员库拆分,拆分成会员1库,会员2库,以userId拆分,userId尾号0-5为1库 6-9为2库,还有其他方式,进行取模,偶数放到1库,奇数放到2库
(2) 表水平拆分
如图把users表拆分成users1表和users2表,以userId拆分,进行取模,偶数放到users1表,奇数放到users2表
水平拆分的其他方式:
- range来分,每个库一段连续的数据,这个一般是按比如时间范围来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了,优点:扩容的时候,就很容易,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了 缺点:大部分的 请求,都是访问最新的数据。实际生产用range,要看场景,你的用户不是仅仅访问最新的数据,而是均匀的访问现在的数据以及历史的数据
- hash分发,优点:可以平均分配每个库的数据量和请求压力 缺点:扩容起来比较麻烦,会有一个数据迁移的这么一个过程
(3) 水平拆分特点
- 每个库(表)的结构都一样
- 每个库(表)的数据都不一样
- 每个库(表)的并集是全量数据
(4) 水平拆分优缺点
优点:
- 单库/单表的数据保持在一定量(减少),有助于性能提高
- 提高了系统的稳定性和负载能力
- 拆分表的结构相同,程序改造较少。
缺点:
- 数据的扩容很有难度维护量大
- 拆分规则很难抽象出来
- 分片事务的一致性问题部分业务无法关联join,只能通过java程序接口去调用
四、分库分表带来的问题
- 分布式事务
- 跨库join查询
- 分布式全局唯一id
- 开发成本 对程序员要求高
五、分库分表技术如何选型
(1) 分库分表的开源框架
- jdbc 直连层:shardingsphere、tddl
- proxy 代理层:mycat,mysql-proxy(360)
jdbc直连层
jdbc直连层又叫jdbc应用层,是因为所有分片规则,所有分片逻辑,包括处理分布式事务 所有这些问题它都是在应用层,所有项目都是由war包构成的,所有分片都写成了jar包,放到了war包里面,java需要虚拟机去运行的,虚拟机运行的时候就会把war包里面的字节文件进行classLoder加载到jvm内存中,所有分片逻辑都是基于内存方进行操作的
(2) proxy代理层
如图,proxy代理层,所有分片规则,所有分片逻辑,包括处理分布式事务都在mycat写好了,所有分片逻辑都是基于mycat方进行操作
(3) jdbc直连层和proxy代理层优缺点
- jdbc直连层性能高,只支持java语言,支持跨数据库
- proxy代理层开发成本低,支持跨语言,不支持跨数据库
---------------------------------------------
分库分表数据库中间件对比
(一)关键问题
1.读写分离
2.分库分表
3.类别
- lib库
1)业务直接到数据库,少一层proxy效率更高
2)没有proxy的lvs的单点问题
- proxy
1)统一管理所有到数据库的连接,连接复用
2)基础查询功能抽象,减少代码耦合
3)易于实现监控、数据迁移、连接管理等功能
(二)sharding-jdbc(开源,lib)
当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架
- 功能
1)以jar包形式提供服务
2)分片灵活,支持等号、between、in等多维度分片
3)sql解析,支持聚合、分组、排序、limit、or等
- 结构
- 特点
1)分片规则:策略自定义、复数分片数
2)JDBC规范重写:针对DataSource、Connection、Statement、PreparedStatement和ResultSet接口封装
3)sql解析:druid
4)sql改写:修改逻辑表名->真实表名;替换不支持的功能,如:avg->sum和count
5)sql路由:单表路由、binding表路由、笛卡尔积路由
6)sql执行:多线程并发执行sql
7)结果归并:遍历类、排序类(归并排序)、聚合类(比较型、累加型、平均型)、分组类
(三)mycat(开源,proxy)
社区爱好者在阿里cobar基础上进行二次开发,解决了cobar的一些问题,且加入了新的功能。
- 功能
1)遵守mysql原生协议
2)基于心跳的自动故障切换
3)支持读写分离,支持mysql主从
4)支持sum、count、max等聚合,支持跨库分页
5)支持服务降级
6)安全,IP白名单、sql注入攻击拦截、prepare预编译
- 原理
拦截:分片分析、路由分析、读写分离分析、缓存分析
(四)DBproxy(开源,proxy)
针对atlas进行改进,形成了新的高可靠、高可用企业级数据库中间件DBProxy
- 功能
1)读写分离
2)负载均衡
3)slave故障感知&摘除
4)连接池
5)自定义sql拦截&过滤
6)流量分组&控制
7)监控状态
(五)atlas
360团队基于mysql proxy把lua用c改写,在高并发下经常会挂掉。
(六)oneproxy(不开源,proxy)
基于mysql协议的数据库中间件。利用c进行开发的,专注于性能和稳定性。
- 功能
透明sql路由(实现后端mysql数据库的集群化部署)和流量分析(为上层应用和底层数据库集群提供丰富的性能监控功能)。
1)复用数据库连接,降低数据库并发连接数
2)即时发现和剔除不可用的后端节点,转发应用请求实现高效故障隔离
3)内置守护进程模式和ha vip机制,确保高可用
4)查询语句分离,跨分片结果集合并,根据分片并行执行sql
5)读写分离
6)对sql语句进行安全检查,拒绝危险的DDL操作
7)分别设置前端应用和后端数据库的sql请求频率,实现QoS控制
8)实时透明分析流量,实时统计sql和事务的运行时间,分析事务的sql结构
- 特点
语言:C&C++开发
网络事件:libevent框架
内存分配:jemalloc优化
QPS:单实例支持40W
连接池:透明连接池的功能,具备mysqk企业版连接池效果
主备:实现透明的读写分离路由
安全:sql请求类别;请求IP;每个sql请求实时检查&拦截
流量分析:IP维度、事务维度展示&分析
稳定:内置高可用、也可与zookeeper等配合
(七)vitess
Youtube上产使用的,架构复杂
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步