1. 为什么要分片
sharding是为了提升系统响应能力。对于数据库来说,为什么sharding会改善性能?
数据库管理数据提供增删改查功能,耗时的部分主要就是CPU计算和IO访问。单表记录规模过大:
- 会增加表索引的大小,进而影响索引的IO读取和内存交换。
- 会增加表数据的文件大小,进而影响最终数据的读取与扫描。
- 记录数过多,在表扫描时需要处理更多未命中的数据。
- 业务上,会提升单表操作并发压力。如果有触发表级锁的操作,会加重影响性能。
服务器单机硬件性能有上限,分表的基础上可以将表再分到不同的物理设备上。
2. 分表设计
分表的设计主要从业务需求上出发,主要是根据数据的查询特点来选择,从表操作SQL中必须的条件字段中选取。
例如:对于用户表,更新与加载主要是按用户操作,所以用户表的分表可以直接按用户id进行hash随机,用户及其关子表,都要和用户表保持一致的分表逻辑,因为用户子表的查询必然也会带着用户id。
分表基础上经常还会带着分库,分库分表后表连接查询就可能不支持了,所以这种情况下,要根据主要的使用场景来进行分表设计。
例如:用户好友关系表,存储用户与其好友的uid映射关系,主要的使用场景是加载好友列表(高频),分表设计时要以所有人用户id来进行分表。这里有一个问题,映射表里只有好友的uid,分库分表情况下又不能直接和用户表进行表连接,那么在加载好友列表时只能遍历按uid去获取好友的名称了。一种改进的方式是,在好友关系表中冗余存储需要随好友列表一起频繁加载的信息(比如姓名),附加同步机制来保证数据及时性。
3. sharding算法
将一个大表的数据拆分到多个表,数据的均匀性是非常重要的,这样才能平摊负载。在shard字段数值分布均匀的前提下,只需要按分表个数直接取模就可以了。
需要注意,最好使用一个素数取模(如果数据没有规律性,用奇数也可以),这样余数分散会较为随机分散,可以使用数据验证下。
1 | SELECT (gcid %9) as p_gcid, count(1) as c1 |
为了方便以后扩容调整shard数量,可以根据数据规模预估一个可能最大shard数,来获得一个较大的余数范围。然后再对余数二次shard。
例如: 先对素数127取模,余数在和7按位与。扩容倍增时,可以有规律的迁移数据,对每个旧shard只需要迁移一半的数据。
- 7 二进制
111
。扩容倍增,模数15二进制1111
。 - shard0=
000
扩容拆成两部分:shard0=0000
和shard8=1000
- shard1=
001
扩容拆成两部分:shard0=0001
和shard9=1001
- etc …
1
2SELECT (gcid %127) &7 as p_gcid, count(1) as c3
FROM crm.customer_crm_search group by p_gcid;
1 | # p_gcid, c1 |