分库分表是互联网企业的常见技术优化手段。主要用于应对高并发、大流量的场景。
解决什么问题
分库、分表虽然总被一起提及,但分库和分表要解决的技术问题是不同的。
| 优化手段 | 解决的问题 |
|---|---|
| 分表 | 解决数据量大导致的B+树高度增加,查询速度下降。 |
| 分库 | 解决数据库容量、CPU、IO资源瓶颈问题解决从库增加造成的主从延迟增加 |
分表
分表通常解决数据量大的问题。当单表行数超过500w后,通常就要考虑分表了。
分表后数据量下降,每个表的B+索引树高度降级。每次索引数据的速度得到提升。
分库
数据库部署在单个主机上,数据库严重依赖单机性能。
在服务发展早期,随着业务扩量,数据库的部署会经历以下过程:
- 业务早期时,通常选择单机部署多DB来节约成本。
- 随着业务发展,单机容量、CPU、IO无法支撑多DB。这时可以选择单机部署单DB,来满足业务诉求。
- 随着业务不断长,普通物理机的内存、磁盘、CPU不足以支撑高性能的DB。这时候可以通过升级主机配置来满足业务发展。
- 业务飞速发展后,主机配置已经几乎达到顶配,升级也越来越困难,单点问题越来越明显。这时就需要用到分库技术了。
当数据库分库后,单机造成的性能问题被极大改善,数据库可以承受的流量极大提高。
分库分表算法
分库分表需要选择一个分表字段来进行分表。利用分表字段可以计算出数据所在的库、表信息。
分表算法通常有以下几种:
直接取模
直接取模的方式比较简单,例如要通过userId字段将表分成128个。则数据所在的表是n%128。
一致性hash
直接取模是比较常用的分表算法,可以让数据比较均匀的分布在多张表中,但是有一个缺点:如果后续需要扩容,可能会涉及数据迁移,扩展性较差。
为了解决这个问题,可以通过一致性哈希算法来分表。
一致性哈希可以通过hash算法将key哈希到一个2^32个节点的空间中,如果后续新增一个节点,只会影响此节点和与他相临的节点。所需要迁移的数据比较少。
全局id生成
分库分表后,需要生成分布式id。在单表中,往往可以通过数据库唯一索引来限制唯一id。但做了分库分表后,唯一索引无法保证不同库表中的id不相同,可能发生主键冲突。
全局id通常作为分表的key。
在生成全局id,在设计的时候通常要遵循以下原则:
- 不重复
- 递增
- 路由相对均匀,不会出现严重倾斜
- 查询速度高
常见的路由key生成方式对比
| 策略 | 不重复 | 递增 | 路由均匀 | 查询速度 |
|---|---|---|---|---|
| 雪花算法 | 满足不重复 | 趋势递增 | 满足路由均匀 | 主键索引 |
| UUID | 满足不重复 | 某些版本满足趋势递增 | 满足路由均匀 | 字符串查询速度慢 |