一、背景

1 背景

用户的不断增多、系统的高可用和越来越多的用户请求、当用户量级和业务提升 数据库无法支持现有业务。

2 问题

1 用户请求量太大

单服务器TPS、内存、IO都是有上限的,需要将请求打散分布到多个服务器

2 单库数据量太大

单个数据库处理能力有限;单库所在服务器的磁盘空间有限;单库上的操作IO有瓶颈

3 单表数据量太大

查询、插入、更新操作都会变慢,在加字段、加索引、机器迁移都会产生高负载,影响服务

二、解决方案

1 垂直拆分

1 垂直分库

业务切割得足够独立,数据也会按照业务切分,保证业务数据隔离,大大提 升了数据库的吞吐能力
image.png

2 垂直分表

image.png

2 水平拆分

1 水平分表

针对数据量巨大的单张表(比如订单表),按照规则把一张表的数据切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。

image.png

2 水平分库

将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合 不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件 资源等的瓶颈

image.png

三、关注(水平拆分)

1 水平分库规则

不跨库、不跨表,保证同一类的数据都在同一个服务器上面。 数据在切分之前,需要考虑如何高效的进行数据获取,如果每次查询都要跨越多个节点,就需要谨 慎使用。一致性HASH 可以考虑

2 水平分表规则

1 RANGE 时间:

按照年、月、日去切分。例如order_2020、order_202005、order_20200501
地域:按照省或市去切分。例如order_beijing、order_shanghai、order_chengdu
大小:从0到1000000一个表。例如1000001-2000000放一个表,每100万放一个表

2 HASH

用户ID取模
不同的业务使用的切分规则是不一样,就上面提到的切分规则,

3 站内信

用户维度:用户只能看到发送给自己的消息,其他用户是不可见的,这种情况下是按照 用户ID hash分库,在用户查看历史记录翻页查询时,所有的查询请求都在同一个库内

4用户表

范围法:以用户ID为划分依据,将数据水平切分到两个数据库实例,如:1到1000W在 一张表,1000W到2000W在一张表,这种情况会出现单表的负载较高
按照用户ID HASH尽量保证用户数据均衡分到数据库中

5流水表

时间维度:可以根据每天新增的流水来判断,选择按照年份分库,还是按照月份分库, 甚至也可以按照日期分库

3 考虑问题

1 主键选择

UUID:本地生成,不依赖数据库,缺点就是作为主键性能太差
SNOWFLAKE:百度UidGenerator、美团Leaf、基于SNOWFLAKE算法实现 数

2 据一致性

强一致性:XA协议
最终一致性:TCC、saga、Seata

3 数据库扩容

成倍增加数据节点,实现平滑扩容
成倍扩容以后,表中的部分数据请求已被路由到其他节点上面,可以清理掉

4 业务层改造

基于代理层方式:Mycat、Sharding-Proxy、MySQL Proxy
基于应用层方式:Sharding-jdbc

5 分库后面临的问题

事务问题:一次投递需要插入两条记录,且分布在不同的服务器上,数据需要保障一致性。 跨
库跨表的join问题
全局表(字典表):基础数据/配置数据,所有库都拷贝一份
字段冗余:可以使用字段冗余就不用join查询了
系统层组装:可以在业务层分别查询出来,然后组装起来,逻辑较复杂

额外的数据管理负担和数据运算压力:数据库扩容、维护成本变高