从分库分表到数据访问层中间件

时间:2023-02-12 01:16:59


因为业务的发展,数据量也在不断的增长,单一数据库无法满足我们读写的性能需求,而分库分表分散存储压力。水平分割,基于数据记录,通过建立结构相同的几张表分别存储数据。垂直分割,基于列字段,将经常一起使用的字段放在一个单独的表中,分割后的表记录之间是一一对应关系。既然是优化,当然也遵循一些原则,完全可以按照下面的优化顺序来,确定当前没有优化的空间,然后才选择终结方案。

从分库分表到数据访问层中间件

1. 背景

  • 为数据库减压
  • 分区算法局限
  • 数据库支持不完善(5.1之后mysql才支持分区操作)
  • 单机的硬件处理能力有限

2. 带来的挑战

id重复问题

  • 借用第三方应用如memcache、redisid自增器
  • 单独建一张只包含id一个字段的表,每次自增该字段作为数据记录的id

水平分表后的路由问题

  • 范围路由,选取有序的数据列作为路由条件,不同分段分散到不同的数据库表中。优点:可以随着数据的增加平滑的扩充新的表,缺点:可能存在数据分布不均匀
  • hash路由,选择某个列(或几个列的组合)的值进行hash运算,然后根据运算结果分散到不同的数据库中。优点:表数据分布比较均匀,缺点:初始表数据量不好选取,扩充新的表数据需要重新分布
  • 配置路由,使用独立的表(或者配置文件等)记录路由配置信息。优点:使用起来简单灵活,扩充表时只需要迁移指定的数据,然后修改路由表。缺点:必须多查询一次,影响整体性能,路由表本身太多影响系统整体性能

join操作问题数据分散在不同的数据库中,无法join查询)

  • 解决:通过业务代码进行join查询,然后结果合并
  • 使用Databus

count操作问题

  • count()相加,在业务代码或者数据库中间件对每个表进行count操作让后再讲杰哥哥相加。优点:实现简单,缺点:性能较低
  • 记录数表,新建一张表,保存数据记录的数量,每次插入和删除子表数据成功后,都更新“记录数表”。优点:性能较高,缺点:实现复杂

order by操作问题

  • 业务代码实现或者数据库中间件查询每个子表的数据,然后汇总进行排序

事务问题(表分散在不同的数据库中,无法通过一个事务修改)

  • 解决:可借助XA协议,tcc柔性事务等

服务器成本问题

开发成本问题,垂直分表会增加表操作的次数等

3. 业界调研

业界组件

简介

实现方案

实现协议

优点

缺点

参考

mysql-proxy

mysql官方提供的mysql中间件服务,上游可接入若干个mysql-client,后端可连接若干个mysql-server,它使用mysql协议,任何连接mysql的上游无需任何更改即可迁移至mysql-proxy上。

代理

 

使用lua语言实现的中间代理服务

支持sql拦截与修改、 性能分析与监控、 读写分离、 请求路由、

不支持分库分表

ref

Atlas

Qihoo 360开发维护的一个基于MySQL协议的数据中间层项目。它实现了MySQL的客户端与服务端协议,作为服务端与应用程序通信,同时作为客户端与MySQL通信

代理

 

对mysql-proxy进行了较大的改进

实现读写分离,功能简单,性能跟稳定性较好

不支持分布式分表;

分表算法不够完善;

ref

Cobar

Cobar是提供关系型数据库(MySQL)分布式服务的中间件,它可以让传统的数据库得到良好的线性扩展,并看上去还是一个数据库,对应用保持透明。

代理

 

实现mysql客户端协议

实现动态数据源、分库分表

使用golang时,事务支持性不好;

不支持读写分离;

ref

Zebra

Zebra是原点评内部使用数据源、DAO以及监控等和数据库打交道的中间件集

非代理

 

jdbc协议层上开发的数据库访问层中间件

实现动态数据源、读写分离、分库分表、CAT监控

接入较为复杂,当时只支持c3p0、Druid、Tomcat JDBC等连接池,且分库分表算法只支持Groovy表达式不易扩展

ref

MTAtlas

原美团DBA团队在开源Atlas基础上做的一系列升级改造

代理

在Atlas基础上支持了分库分表

在读写分离、单库分表的基础上,完成了分库分表的功能开发

当时还处于测试阶段,暂不推荐业务方使用

 

TDDL

整个淘宝数据库体系里面具有非常重要的一个中间件产品,在公司内部具有广泛的使用

非代理

基于jdbc规范

应用透明的分库分表层 和 具有众多特性的动态数据源

虽开源,但社区一点也不活跃

ref

sharding-sphere

他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能

两种都可以

 

 

非常流行

ref

注:非代理表示无server,client-jar形式存在,代理表示代理server

设计目标

性能、可拓展性

功能特性

  • 动态数据源
  • 读写分离
  • 分布式唯一主键生成器
  • 分库分表
  • 连接池及SQL监控
  • 动态化配置

4. Databus

项目范围越大,分库难度越高。有时候,一句复杂的SQL能够涉及四五个业务方,这种SQL都是需要重点关注的。确定分库分表的规模,是只分其中的几张表,还是全部涉及。分的越多,工作量越大,几乎是线性的。分库分表会重新影响数据的分布,无论是全量还是增量,都会涉及到数据迁移,所以Databus是必要的。

一种理想的状态是所有的增删改都是消息,可以通过订阅MQ进行双写。但一般情况下,仍然需要去模拟这个状态,比如使用日志增量订阅的组件。

从分库分表到数据访问层中间件

从分库分表到数据访问层中间件

最后,确定方案还是需要深度思考,选择合适的时机及项目进行验证落地。