一、数据切分

关系型的数据库本身是比较容易成为系统瓶颈的,单机存储容量、连接数、CPU的处理能力等都是有限的。单表的数据量达到一定量后,由于查询的维度较多,就算添加索引,优化索引,优化查询语句,都难以提高查询性能时,就要考虑切分了,切分的目的就是减少数据库的压力,缩短查询时间。

数据库分布式的核心就是数据切分Sharding)。

数据切分一般分为两种:垂直(纵向)切分,水平(横向)切分。

1.1 垂直(纵向)切分

垂直切分:垂直分库和垂直分表

垂直分库

根据业务耦合性,将关联性低的不同表表存储在不同的数据库。做法和将大系统拆分为多个小系统类似,按照业务分类进行划分。与”微服务治理“做法相似,每个微服务单独使用一个数据库。

垂直分库

垂直分表

基于数据表中的列进行拆分,某个表的字段较多,就可建立扩展表,将不常用的或字段长度较大的字段拆分出去到相应的扩展表里。一般根据主键关联数据。这样拆分也能避免跨页问题,Mysql底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。

垂直分表

垂直拆分的优缺点分析

优点

  • 解决业务耦合的问题,使业务更加清晰
  • 与微服务治理类似,也能对不同业务的数据进行分级管理。维护、监控等
  • 高并发场景下,垂直拆分能在一定程度 上提升IO,数据库连接数,单机硬件资料瓶颈

缺点

  • 部分表无法join,只能通过接口聚合方式解决,提升了开发难度
  • 分布式事务处理更复杂
  • 依然存在单表数据量过大,需要水平拆分

1.2 水平(横向)切分

当一个应用很难再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。

水平切分分为库内分表分库分表,是根据表内的内在逻辑关系,将同一个表按不同的条件分散到不同的数据库或多个表中,每个表只包含一部分数据,从而使单个表的数据量变小,达到分布式的效果。

横向拆分

上图就是分库分表,同样的表按照不同的条件拆分到不同的数据库,达到单表单库的数据库减少。

库内分表只解决了单表数据量大的问题,并没有把表分布到不同的机器上,所以对于减轻数据库的压力来说,帮助不大,因为还是在竞争同一个物理机的CPU、内存、网络IO等资源。

水平切分的优点

  • 不存在单库数据量大的问题,高并发的瓶颈问题,提升系统的稳定性和负载能力
  • 应用端不需要拆分业务

缺点

  • 跨分片的事务难以保证
  • 跨库的join关联查询性能差
  • 数据多次扩展难度和维护量极大

水平拆分后,同一个表能存在多个数据库/表中,每个表的数据不同。几种常见的分片规则:

1.根据数值范围

根据时间区间或者ID区间来区分。

  1. 按照日期将不同月/日的数据分散到不同的数据库中;
  2. 按照id区间,将1~9999的记录分到第一个库,10000~19999分到第二个库,以此类推
  3. 按照id的奇偶性来分,不过这样只能分两个
  4. 冷热数据分离,热点数据和不常用的数据分到不同的数据库,也是类似的实践

优点:

  • 单表大小可控
  • 天然便于水平扩展,后期想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
  • 使用分片字段(比如id)进行范围查找时,能快速定位到分片位置,有效避免跨分片查询的问题

2.根据数值取模

采用hash值取模的切分方式。

根据表中具有唯一值的字段进行hash运算,在用hash值对数据库数量进行取模mod,得到的值就是这个记录要分到哪个数据库的编号。

优点

  • 数据分片比较均匀,不容易出现热点和并发访问的瓶颈问题

缺点

  • 后期分片集群扩容,需要迁移旧的数据(使用一致性hash算法可以规避这个问题)
  • 当查询的条件中不包含做hash运算的分片字段时,这个时候就不知道数据在哪个库,就必须全库查询,再在内存中合并数据后返回会应用,分库反而成为负担