范围法
以业务主键uid为划分依据,将数据水平切分1到两个数据库实例中:
db_1:存储0到1千万的uid数据
db_2:存储1到2千万的uid数据
范围法的优点:切分策略简单,根据id,按照范围,业务很快能够定位到数据在哪个数据库上。扩容简单,如果容量不够,只要增加db_3就行
缺点:id必须满足递增的特性(并不建议使用自增ID或者UUID作为数据库的主键)
数据量不均,新增的db_3在初期的数据会比较少
请求量不均,一般来说,新注册的用户活跃度会比较高,故db_2往往会比db_1负载要高,导致服务器利用率不平衡
哈希法
也是以用户中心的业务主键uid为划分依据,将数据水平切分到两个数据库实例上去:
db_1:存储id取模得1的uid数据
db_2:存储id取模得0的uid数据
哈希法的优点:切分策略简单,根据uid,按照hash,业务很快能够定位到哪个数据库上;
数据量均衡,只要uid是均匀的,数据在各个库上的分布一定是均衡的;
请求量均衡,只要uid是均匀的,负载在各个库上的分布一定是均衡的;
缺点:扩容麻烦,如果容量不够,要增加一个库,重新hash可能会导致数据迁移,如何平滑的进行数据迁移,是一个需要解决的问题
索引表法
思路:id能直接定位到库,数据不能直接定位到库,如果通过id能查询到db,问题解决
解决方案:建立一个索引表记录id→db的映射关系,用id来访问时,先通过索引表查询到id,再定位相应的库
索引表属性较少,可以容纳非常多数据,一般不需要分库
如果数据量过大,可以通过id来分库
优点:节点扩容无影响
缺点:多一次数据库查询,性能下降一倍
缓存映射法
思路:访问索引表性能较低,把映射关系放在缓存里性能更佳
解决方案:查询先到缓存cache中查询id,再根据id定位数据库,假设cache miss,采用扫全库法获取对应的id,放入cache
id到db的映射关系不会改变,映射关系一旦放入缓存,不会更改,无需淘汰,缓存命中率超高
如果数据量过大,可以通过id进行cache水平切分
缺点:多一次cache查询
基因法(暂不了解)
业务标识 基因融入id
思路:可以从业务标识抽取“基因”,融入id中
假设分8库,采用id%8路由,潜台词是,id的最后3个bit决定这条数据落在哪个库上,这3个bit就是所谓的“基因”。
解决方案:
在插入数据时,设计函数业务标识生成3bit基因,sign_gene=f(k),如上图粉色部分
同时,生成61bit的全局唯一id,作为用户的标识,如上图绿色部分
接着把3bit的lsign_gene也作为uid的一部分,如上图屎黄色部分
生成64bit的uid,由id和sign_gene拼装而成,并按照uid分库插入数据
用k来访问时,先通过函数由k再次复原3bit基因,sign_gene=f(k),通过sign_gene%8直接定位到库
【动态扩容解决方案之hash环迁移法】
一致性哈希算法将整个哈希值空间映射成一个虚拟的圆环,整个哈希空间的取值范围为0— 2 32 2^{32} 232-1。整个空间按顺时针方向组织。0— 2 32 2^{32} 232-1在零点中方向重合。接下来使用Hash算法对服务请求进行映射,将服务请求使用哈希算法算出对应的hash值,然后根据hash值的位置沿圆环顺时针查找,第一台遇到的服务器就是所对应的处理请求服务器。当增加一台新的服务器,受影响的数据仅仅是新添加的服务器到其环空间中前一台的服务器(也就是顺着逆时针方向遇到的第一台服务器)之间的数据,其他都不会受到影响。综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性;