共计 1246 个字符,预计需要花费 4 分钟才能阅读完成。
在高并发的场景中,单库曾经不能满足性能的要求,这才有了数据库演进之路。
单个分片
partition key 两种形式:范畴和 hash。
范畴的话比方用户的注册工夫、用户的地理位置。毛病是热点调配不平均,比方北上广的客户群里多,新注册的用户比拟沉闷,导致这些热点库的压力会比拟大。
散列的话比方依据用户的 id 进行 hash。长处是每个库的读写压力大概率是平均的,毛病是扩容不不便。
多个分片
多个分片的场景,就是可能依据多个维度进行查问。比方用户表的 partition key 是 id,那咱们能够依据 hash(id) 晓得查问哪个库。如果用户表的 partition key 是 uname,咱们也能够依据 hash(uname) 晓得查问哪个库。如果咱们设置 id 为 partition key,那依据 uname 查问的时候,就不晓得对应的库在哪里,此时就要全库搜寻。
双写
同时下两个数据库,如果依据 id 查找,那去依据 id 分片的数据库查问,如果依据 uname 查找,那去依据 uname 分片的数据库查问。这个计划,尽管防止了全库搜寻,然而用空间换工夫的代价有点大啊,而且插入的时候还要保障数据库的一致性。
索引
插入数据库的时候,同步更新 uname 在哪个数据库。依据 uname 查问的时候,先查问 uname 在哪个库,而后依据这个值去指定的数据库查问。
毛病:
- 同样也是双写,须要保证数据的一致性。
- 读取的时候,多查问了一次,影响性能。
- 扩容的时候,须要更改表数据信息。
基因法
既然不晓得对应关系,那就插入数据的时候,就给个标识符。
基因法(假如模 16):
- username 取后 4 位
- id 生成 60 位
- 把 username 的后 4 位加到 id 前面
模 16= 2 的 4 次方,所以是取 4 位。这样不论是对 uname 取模,还是对 id 取模,实际上都是对这两个的后 4 位取模,通过基因法,这后 4 位是落在一个数据库上的,所以不论通过 uname 还是 id,都能找到对应的数据库。
扩容计划
停机扩容
这个计划比拟暴力,个别在没什么人用零碎的时候,比方凌晨,间接把零碎停了,停机之前挂个布告告诉几点到几点不能用。如果数据量比拟大的话,还可能在这个工夫做不完。。。
双写
首先,写一个同步的工具,把旧数据库的信息写到新数据库。在应用层中,每次查问走的是旧数据库,对数据库的批改、删除、新增,两个库都要操作。因为同步工具和应用层都会对数据库进行操作,所以有可能反复操作某个数据,此时每个表须要一个操作工夫,以工夫比拟新的数据为准。
从库转主库
如下图所示,每个数据库都有对应的从库。迁徙的时候间接把从库该主库就好。
上面是每个数据库的数据以及主从的状况:
此时把 3 个数据库变成 6 个数据库,也就是从 id%3 变成 id%6。
以 id%3= 1 的为例,之前数据为 1,4,7,10,13,16,19 的 id 会读取 id%3= 1 的数据库,扩容后,1,7,13,19 的 id 会读取 id%6= 1 的数据库,而 4,10,16 的 id 会读取 id%6= 4 的数据库。
这种形式,迁徙简直不必导入数据,能够霎时切换,毛病就是数据冗余,须要在扩容后,把多余的数据清空。