P: 今天我们聊一下关于数据切片的方法
S: 好
P: 有时候我们会碰到数据量太大,单点容量无法支撑的情况,这时候我们会需要进行分库。
S:嗯,是的,基于硬件成本的考虑,我们不可能一性次分库到位,一般是随着数据量的增长逐次扩容分库。
P: 是的,所以在定分库方案的时候还需要考虑以后的扩容方案。
S:比如我们是通过USERID来进行分库:
一般有两种方法:
1)用DB来实现
2)用HASH算法
P: 逐个简单描述一下。
S: 用RDB(关系数据库)来实现 :
将每个USERID对应的DBID记录下来,应用程序在启动时将所有对应关系数据放在MEM CACHE中,
当用户数据来访问时,先去取得这个USERID对应的DBID,再进行相应的访问.
P: 有没有抽象表可以参考
S: 嗯。
create table dbinfo ( dbid int , ip varchar(20) , port varchar(20) ) comment “DB 信息表”
create table user_db ( userid int , dbid int ) comment “USER与DB对应表” ;
create table user_data (userid int , userdata varchar(3000)) comment “用户数据表“;
P: 用户登陆时,怎么找相应的库?
S: 所以在MEMCACHE里找,如果没有,就到库里找:select db_id from user_db where userid=? ;
找到了DBID也就找到了数据源了;
P: 那新用户进来,有多个DB时,按什么规则进行分配
S: 比较简单的是进行平均分配;
P: 那我扩容了怎么办?原来有2个库,我新加了一个库,如果再按平均分配,不是前面的2个库到一定的时候会爆掉?
S: 我们可以在dbinfo表里加一个权重字段,如果是新库,权重设置大一点;这样大多数新用户会往新库里去;如果老的库不想增加新用户,可以把权重设置成0;
P:如果老的数据库,虽然新用户增加了; 但用户的数据一直在增加,导致单点支撑不了,怎么办?
S:这时有两种方法:
1) 把用户的数据迁到其他的库,并同时在user_db表中更改对应关系;
这样的迁移只能由应用来逐个完成; 并且迁移速度比较慢;
2) 在数据库级别作复制拆分;
把一个DB,复制一份出来,这时你拥有两份相同的数据;
这里应用只需要一边刷新MEMCACHE的对应,一边把DB里的对应改掉;速度快了很多;
P: 你还有一种切片思路呢?
S: 对于第2种切片思路,用HASH算法,在DB这一级别完成;迁移扩容也很快;
P: 嗯。
S: 假如有应用,每个USER的数据量是基本一样的; 不会出现某个用户的数据量特别的情况;那么我们从用户数来考虑就可以;另外通过我们的评估,假设1024个服务器绝对能满足这个应用(当前我还没有碰到过这么大的MYSQL应用)
P: 嗯。
S: 我们先将每一个MACHINE(物理机)上只启一个MYSQL实例;
S: 我们可以直接建1024个数据库;
db0001 — db1024 ; 开始,用户量很少; 我们可以将这1024个DB都放在同一个MACHINE1里;
P: 数据大了咋办?
S: 拆
当用户量开始增长; 那么我们可以将MACHINE1中的部分库迁出来;放在MACHINE2里;
这里我们还需要有一个HASH值与连接池的对应关系表;
DB_HASH值 — MACHINE NUM
————————
100 1
400 2
600 3
1024 4
用户进来,根据USER_ID进行HASH后, 比如VALUE=300,在2号库里去找库:DB0300;
P: 哦,我们还可以将100–400 拆成 100–200,201–400 是吧。
S: 对的。
P: 直到拆到1024个MACHINE;
S: 这样HASH,在DB0001 – DB1024 中的用户数是应用是相对均匀的;
扩容也只要把部分的库导到新的MACHINE中,比较方便;
P: 那如果我们已经拆到1024个库了,在单个库中,用户数据量特别的大,出现单点支持不了的情况;
S: 嗯,这种情况还是存在的,如果真有这么大的数据量,只能用二级HASH了。
P: HASH 到表级?
S: 对。
DBHASH值 TABHASH值 MACHINE_NUM
————————————
1 600 1
1 1024 10
400 2
600 3
1024 4
不过这种切片方法还有一个缺点就是不支持单用户级别的迁移;
P: 哦;明白了; 有没有其他的思路了?
S: 我相信肯定还有更好的方法和思路。 路过的千万别忘了把好方法写上;