共计 1495 个字符,预计需要花费 4 分钟才能阅读完成。
一、数据切分
关系型的数据库本身是比较容易成为系统瓶颈的,单机存储容量、连接数、CPU的处理能力等都是有限的。单表的数据量达到一定量后,由于查询的维度较多,就算添加索引,优化索引,优化查询语句,都难以提高查询性能时,就要考虑切分了,切分的目的就是减少数据库的压力,缩短查询时间。
数据库分布式的核心就是数据切分(Sharding)。
数据切分一般分为两种:垂直(纵向)切分,水平(横向)切分。
1.1 垂直(纵向)切分
垂直切分:垂直分库和垂直分表
垂直分库
根据业务耦合性,将关联性低的不同表表存储在不同的数据库。做法和将大系统拆分为多个小系统类似,按照业务分类进行划分。与”微服务治理“做法相似,每个微服务单独使用一个数据库。
垂直分表
基于数据表中的列进行拆分,某个表的字段较多,就可建立扩展表,将不常用的或字段长度较大的字段拆分出去到相应的扩展表里。一般根据主键关联数据。这样拆分也能避免跨页问题,Mysql底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。
垂直拆分的优缺点分析
优点
- 解决业务耦合的问题,使业务更加清晰
- 与微服务治理类似,也能对不同业务的数据进行分级管理。维护、监控等
- 高并发场景下,垂直拆分能在一定程度 上提升IO,数据库连接数,单机硬件资料瓶颈
缺点
- 部分表无法join,只能通过接口聚合方式解决,提升了开发难度
- 分布式事务处理更复杂
- 依然存在单表数据量过大,需要水平拆分
1.2 水平(横向)切分
当一个应用很难再细粒度的垂直切分,或切分后数据量行数巨大,存在单库读写、存储性能瓶颈,这时候就需要进行水平切分了。
水平切分分为库内分表和分库分表,是根据表内的内在逻辑关系,将同一个表按不同的条件分散到不同的数据库或多个表中,每个表只包含一部分数据,从而使单个表的数据量变小,达到分布式的效果。
上图就是分库分表,同样的表按照不同的条件拆分到不同的数据库,达到单表单库的数据库减少。
库内分表只解决了单表数据量大的问题,并没有把表分布到不同的机器上,所以对于减轻数据库的压力来说,帮助不大,因为还是在竞争同一个物理机的CPU、内存、网络IO等资源。
水平切分的优点
- 不存在单库数据量大的问题,高并发的瓶颈问题,提升系统的稳定性和负载能力
- 应用端不需要拆分业务
缺点
- 跨分片的事务难以保证
- 跨库的join关联查询性能差
- 数据多次扩展难度和维护量极大
水平拆分后,同一个表能存在多个数据库/表中,每个表的数据不同。几种常见的分片规则:
1.根据数值范围
根据时间区间或者ID区间来区分。
- 按照日期将不同月/日的数据分散到不同的数据库中;
- 按照id区间,将1~9999的记录分到第一个库,10000~19999分到第二个库,以此类推
- 按照id的奇偶性来分,不过这样只能分两个
- 冷热数据分离,热点数据和不常用的数据分到不同的数据库,也是类似的实践
优点:
- 单表大小可控
- 天然便于水平扩展,后期想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
- 使用分片字段(比如id)进行范围查找时,能快速定位到分片位置,有效避免跨分片查询的问题
2.根据数值取模
采用hash值取模的切分方式。
根据表中具有唯一值的字段进行hash运算,在用hash值对数据库数量进行取模mod,得到的值就是这个记录要分到哪个数据库的编号。
优点
- 数据分片比较均匀,不容易出现热点和并发访问的瓶颈问题
缺点
- 后期分片集群扩容,需要迁移旧的数据(使用一致性hash算法可以规避这个问题)
- 当查询的条件中不包含做hash运算的分片字段时,这个时候就不知道数据在哪个库,就必须全库查询,再在内存中合并数据后返回会应用,分库反而成为负担