分库分表

业务场景

随着单库单表数据量越来越大,造成性能下降,需要拆分库表降低单库单表压力

拆分方式

垂直拆分

按业务模块拆分,不同业务模块独立为单独的库
拆分多列表为多表,减少表的列数

水平拆分

把大数据量单表拆分成多表,例如表数据为1000w,拆分成两个500w的单表
这里每个表也可以拆分到不同的数据库

拆分算法

  • 按照唯一 ID 求模,将数据分散到不同的数据库表
  • 按照范围区间,将不同区间的数据拆分到不同库表

拆分需要解决的问题

  • 数据库原支持的聚合函数受限
  • 表自增id不能再使用数据库的实现
  • 业务需要改造才能支持使用
  • 跨库事物
  • 数据难以维护

相关的中间件

名称 简介
cobar 提供关系型数据库(MySQL)分布式服务的中间件,它可以让传统的数据库得到良好的线性扩展,并看上去还是一个数据库,对应用保持透明。
mycat 社区爱好者在阿里cobar基础上进行二次开发
TDDL 淘宝团队开发的,属于 client 层方案。支持基本的 crud 语法和读写分离,但不支持 join、多表查询等语法。目前使用的也不多,因为还依赖淘宝的 diamond 配置管理系统。
DRDS 阿里巴巴自主研发的分布式数据库服务(此项目不开源),DRDS脱胎于阿里巴巴开源的Cobar分布式数据库引擎,吸收了Cobar核心的Cobar-Proxy源码,
Atlas 360 开源的,属于 proxy 层方案,以前是有一些公司在用的,但是确实有一个很大的问题就是社区最新的维护都在 5 年前了。所以,现在用的公司基本也很少了。
DBProxy DBProxy是美团点评DBA团队针对公司内部需求,在奇虎360公司开源的Atlas做了很多改进工作,形成了新的高可靠、高可用企业级数据库中间件
sharding-JDBC sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架
other 其他比如网易,58,京东等公司都有自研的中间件。
主要分为proxy和client模式

无论是client模式,还是proxy模式,几个核心的步骤是一样的:SQL解析,重写,路由,执行,结果归并

  • proxy
    • mycat或者cobar,shading-proxy
    • 需要独立部署,单机模式无法保证可靠性,一旦宕机则服务就变得不可用,不得不引入HAProxy来实现它的高可用集群部署方案, 为了解决HAProxy的高可用问题,又需要采用Keepalived来实现。
    • 分库分表
  • client
    • shading-jdbc
    • 对应用透明,由应用业务方配置分库分表策略
    • client模式,它架构简单,性能损耗也比较小,运维成本低
    • 分库分表

存在的问题和方案

  • 不同方案存在优缺点需要根据具体业务场景选择合适的方案
    • hash/mod (扩容问题)
    • range (热点问题)
  • 一般会使用hash方法,但是会有扩容问题
    • 解决方案
      • 避免扩容
        • 上来我们就使用较大的分库分表数量,例如32 * 32,避免后续再进行扩容(一个表可以被拆分为1024个表,大概可以支撑1024*500=512000w=51亿数据量,基本能够满足大多数公司需求)
        • 这里开始的库可以是虚拟库,都在一个服务器上,后续可以独立服务器,只需要把库数据迁移过去,应用修改下库地址即可
      • 区分旧的规则和扩容后的规则
        • 通过时间区分旧的路由规则和新的路由规则(路由的id必须可以解析到时间-例如雪花算法就可以)
      • 下面会单独梳理解决扩容和热点的方案
  • 进行分库分表后,线上数据怎么迁移到新的分库分表模式中
    • 方案
      • 增加影子服务,同步线上数据到分库分表模式,
      • 待验证后,独立同步旧数据到新的数据库服务,
      • 停止旧数据模式
  • 分库分表后特殊查询问题,join,group by ,分页等
    • 跨节点多库进行查询时,会出现limit分页、order by排序等问题。分页需要按照指定字段进行排序,当排序字段就是分片字段时,通过分片规则就比较容易定位到指定的分片;当排序字段非分片字段时,就变得比较复杂了。需要先在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序,最终返回给用户.
    • 类似sharding-jdbc 其已经对常用已经支持,但是业务使用还是应该尽量避免使用复杂查询,避免查询条件没有分片字段,这样会使其进行所有库的查询操作。
    • 更好的方案是,对分库分表数据不使用复杂查询,如果有复杂查询需求,引入es来解决
      • 这里依然会引入新的问题,后续如果业务继续膨胀积累,es会成为瓶颈,
      • 解决方案是对es进行瘦身,不存储具体数据,只存储索引(对应hbase的rowkey),具体数据存储到hbase。
  • 全局主键问题
    • uuid
    • 单独使用mysql库表来生成主键
    • 雪花算法
  • 夸库事物问题
    • 如果 业务已经做了微服务处理,已有微服务事物处理方案,可以使用微服务方式完成
    • 分布式事物相关
  • 数据库连接数过多(mysql最大支撑16384个连接数,默认100)
    • 使用client中间件后,每个应用都连接了n个库,每个应用都维持了一个数据库连接池,假设有30个应用,连接池维持8个连接数,每个mysql需要支持240个连接数,那么如果应用超过2048(已经超过mysql支持的最大上限),而且微服务中大多是虚拟的应用,也就是说多个应用会连接同一个mysql,会急剧达到瓶颈。

分片算法扩容和热点方案

  • 参考了网上大牛分享的方案整理如下
  • hash/mod+range
    • 抽象group,group按区间划分
    • 每个group包含n个库和m个表,
    • 路由到group的数据再根据总表数进行取模路由到库
    • 然后在通过range路由到具体表
    • 分库分表
      这里可以支持动态进行扩容,复用空间,也基本最大程度的避免了热度问题