题记:本篇博客主要是对美团订单系统分库分表系统的一些解析和加入了自己的理解,纯粹是做笔记,长知识吧,不会构成侵权吧…..
分库分表
缘由
- 订单系统过于庞大
- 索引混乱(索引的建立需要在识别度高一点的字段建立,老重复的就不要了)
- 查询慢
- 表数据量大
解决办法
垂直切分
- 垂直切分是什么意思?
简单来说就是竖着切,试想一下,把一个库中很多张表竖着切,这些表就会散开,其实垂直切分就是这个意思,将不同模块的表放到不同的数据库中,比如支付的放在支付数据库,用户的放在用户数据库,会员的放在会员数据库等等,可以减少耦合性。
水平切分
- 含义
将某张访问非常频繁的表,按照某个特定的规则(通常是某个字段进行hash),然后将数据分散到多个表,甚至是多个数据库中,这样每张表或者每张库都含有一部分数据。
- 实例
从美团数据库分片出发
(1) 查询切分
首先数据库分片,将sharding key记录在一个单独的库中
你每次要查询数据库的时候,请先到mapping db里面去查一下你应该到那个数据库去拿数据。
思考:这个mapping db是否真的有需要,是否shading key提供一种约定,比如说根据用户id来进行hash进行分散到不同的数据库中。当然这只是一种分片策略,如果你觉得慢,可以把这个表结构缓存在内存中。这样就很快了
(2)范围切分
按照范围来切分,比如说按照时间范围和ID的范围来进行切分
比如说用户的id是0-1000000的,请到第一个数据库中去查询,优点是每张表的大小是可以控制的,缺点是集中写入时候,数据库压力过大
(3)Hash切分
一般使用取模运算来进行切分,也就是Mod切分,图中db mod代表db取模,tb mod代表tb取模
解释:比如分库分表的方案是32个数据库实例,通过userId进行取模的话就是,将UserId后面4位模32然后丢到32个数据库中,同时又将UserId后面4位除以32再mod32丢到32张表里面,这样就有1024张表,然后线上部署8个主从实例,每个实例4个数据库。完毕。
问题: 为什么是32个实例,我没有那么大的规模怎么办
回答: 其实32个只是个demo,但是我们这里hash规则一定要满足一致性hash,而恰巧mod 2的n次方这种就是一致性hash,所以你的数据库实例可以是2/4/8/16/32等
问题:为什么是取后四位
回答:因为美团订单把用户后四位融到订单号里面了,然后订单号方案是时间戳+用户4位标识码+随机数,没有使用单一的集群方案
问题:为什么这种易于扩展?
回答:现在是8个主从实例,以后如果数据库到瓶颈了那么就可以部署32个集群,甚至1024个集群,一个表一个数据库一台ip****
实践(数据迁移)
上面方案有了,接下来是怎么实践了。
首先垂直拆分:垂直拆分之后就会有很多的数据库,然后代码里面就要配置多个数据源,然后根据要求去不同的数据源拉取数据了
然后讲讲水平拆分:
加入有一张微博表:
create table weibo (
id int primary key auto_increment comment '主键',
user_id int comment '发微博的用户id',
create_at datetime comment '创建时间',
...其他字段
) comment '微博';
单库情况下查询当前最新20条微博的SQL语句为:
select * from weibo order by create_at desc limit 20;
分库情况下的SQL语句为:
use db_1;
select * from weibo order by create_at desc limit 20;
use db_2;
select * from weibo order by create_at desc limit 20;
use db_3;
select * from weibo order by create_at desc limit 20;
然后你需要对这60个最新的,然后进行排序,找出个前20个最新的出来。top k问题
总而言之:水平拆分会把业务变得非常复杂,能用垂直拆分解决就尽量用垂直拆分,不要用水平拆分。尽量使用对业务影响较小的读写分离,垂直分库等方案
然后还有一点是,既然在不同的数据库中,那么id可能会相同,所以就不要用自增了。