场景
假设我们一条帖子的字段包含:帖子ID,发起的用户ID
先考虑一个业务,用户要发帖子,数量很大,需要分库分表,如何进行拆分
业务:查询用户的所有帖子、查询帖子详情。
目的: 把同用户的帖子放到一个库
普通水平切分:
根据帖子ID切分则无法一次查询用户的所有帖子,只能一个个库按用户查询;
根据用户ID切分则需要先查帖子所属用户,定位到这个用户在哪个库,再从这个库查这个帖子;
所以要达到上面的目的就只能想虽的方法
什么是分库基因?
通过uid分库,假设分为16个库 (2的四次方),采用uid%16的方式来进行数据库路由,这里的uid%16,其本质是uid的最后4个bit决定这行数据落在哪个库上,这4个bit,就是分库基因。
什么是基因法分库?
image.png
如上图所示,uid=666的用户发布了一条帖子(666的二进制表示为:1010011010):
使用uid%16分库,决定这行数据要插入到哪个库中
分库基因是uid的最后4个bit,即1010
在生成tid时,先使用一种分布式ID生成算法生成前60bit(上图中绿色部分)
将分库基因加入到tid的最后4个bit(上图中粉色部分)
拼装成最终的64bit帖子tid(上图中蓝色部分)
这般,保证了同一个用户发布的所有帖子的tid,都落在同一个库上,tid的最后4个bit都相同,于是:
通过uid%16能够定位到库
通过tid%16也能定位到库
基因法为什么能实现这个特性和其他应用
利用了基因的思想,从一个维度的信息里,摘取了一个分库基因,其他维度信息里也全会带上
,使得所有维度的信息都能通过此分库基因完成分库
此思想也可以用于这类分流系统中
java实现
下面是java实现的抽取基因片断的逻辑,最后生成的这个片断会拼到id上。 反过来取数据时怎么取了? 比如只知道用户id或帖子id时。怎么确定数据在哪个库呢?
用户id: 比如666,直接%16,得到10,就是在库10
帖子id: 因为帖子id目前组成是 uuid+基因(1010), 所以,可以先截取得到基因,然后二进制转进帛得到10,也就知道在库10上了
/**
* [ id 抽取基因 ]
* @param n [要抽取的id]
* @return [收取的基因]
*/
public static String binaryToDecimal(int n)
{
return String.format("%04d",Integer.valueOf(Integer.toBinaryString(n%16)));
}
public static void main(String []args) {
int n = 10;
String j = binaryToDecimal(n);
System.out.println(j);
}