[KANMARS原创] - 分布式系统一致性hash中的key-全局唯一ID生成器
分布式系统一致性hash中的key
–曾经和公司一个大神讨论分布式系统架构,提起一致性hash,他曾经给介绍了一种一致性hashkey的生成方式,例如一个long型数据,第0位存标志位,1-8位存放国家,9-16位存放省,17-24位存放城市,25-27位存放机房编号,28-30位存放集群编号,31-38存放物理机实例编号……….最终生成的一致性hash再通过环形hash空间完成负载均衡,借此实现高并发系统。
万事都是想起来容易,做起来难。
例如分布式系统一致性hash的全局ID生成器,前段时间公司貌似需要写一个,由于项目紧张,我们直接使用的是创建的一个NumberCreateUtil的简版工具类。
“粗略的”实现了全局唯一ID生成,
近日进行了反省,是因为“没有技术积累”,例如一些简单的工具没有,比如全局唯一ID生成器,例如短链接生成器之类的。
因此写了一个全局ID生成器+long数据可见性转换工具。
大概原理是:传入时间,国家,城市,集群,机器,随机数,用户ID,生成一个long数据,可以作为一致性Hash的唯一的key
代码如下:
——————————————————————————-IDCreaterUtils——————————————————————————————————
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/
ID生成器
@author baolong
/
public class IDCreaterUtils {
/
系统创建时间
/
public static final long BEGIN_TM = new Date(115,9,10).getTime();//
/正负号掩码,0位为0,其余为1*/
public static long MASK_FLAG = 0x7FFFFFFFFFFFFFFFL;
/
所有掩码之和为0x7FFFFFFFFFFFFFFFL;
/
/时间掩码,长度29,范围限定[0-536870912],[1-29]位为1,其余为0,秒为单位,够用17年*/
public static long MASK_TIME= 0x7FFFFFFC00000000L;
/国家掩码,长度3,范围限定[0-8],[30-32]位为1,其余为0/
public static long MASK_COUNTRY=0x0000000380000000L;
/**城市掩码,长度6,范围限定[0-63],[33-38]位为1,其余为0/
public static long MASK_CITY = 0x000000007E000000L;
/集群掩码,长度2,范围限定[0-3],[39-40]位为1,其余为0*/
public static long MASK_CLUSTER = 0x0000000001800000L;
/机器掩码,长度6,范围限定[0-63],[41-46]位为1,其余为0/
public static long MASK_MACHINE = 0x00000000007E0000L;
/**随机数掩码,长度7,范围限定[0-127],[47-53]位为1,其余为0/
public static long MASK_RANDOM = 0x000000000001FC00L;
/用户ID掩码,长度10,[54-63]位为1,其余为0*/
public static long MASK_USER = 0x00000000000003FFL;
/
64位ID生成器,正数
@param time 时间,[1-29]位,长度29,范围限定[0-536870912],以秒为单位,够用17年,如果该参数传递为0,则默认使用当前时间
@param country 国家,[30-32]位,长度3,范围限定[0-8]
@param city 城市,[33-38]位,长度6,范围限定[0-63]
@param cluster 集群,[39-40]位,长度2,范围限定[0-3]
@param machine 机器,[41-46]位,长度6,范围限定[0-63]
@param random 随机数,[47-53]位,长度7,范围限定[0-127]
@param user 用户ID尾数,[54-63]位,长度10,范围限定[0-1023]
@return
/
public static long createId(long time,long country,long city,long cluster,long machine,long random,long user) throws Exception {
if(time<0 || time > 536870911 ){
throw new Exception(“time时间范围超出[0-536870912]”);
}
if(country<0 || country> 7){
throw new Exception(“国家范围超出[0-7]”);
}
if(city<0 || city> 63){
throw new Exception(“城市范围超出[0-63]”);
}
if(cluster<0 || cluster> 3){
throw new Exception(“集群范围超出[0-3]”);
}
if(machine<0 || machine> 63){
throw new Exception(“机器范围超出[0-63]”);
}
if(random<0 || random> 127){
throw new Exception(“随机数范围超出[0-127]”);
}
if(user<0 || user> 1023){
throw new Exception(“用户ID尾数范围超出[0-1023]”);
}
long result = 0;
long time_base = time;
if(time_base ==0){
time_base = (System.currentTimeMillis() - BEGIN_TM)/1000;
}
result = result | ((time_base << (63 - 29)) & MASK_FLAG );
result = result | ((country << (63 - 32)) & MASK_COUNTRY );
result = result | ((city << (63 - 38)) & MASK_CITY );
result = result | ((cluster << (63 - 40)) & MASK_CLUSTER );
result = result | ((machine << (63 - 46)) & MASK_MACHINE );
result = result | ((random << (63 - 53)) & MASK_RANDOM );
result = result | ( user & MASK_USER );
return result;
}
/
传入一个ID,解析为LONG数组
@param id
@return
new long[]{
time,
country,
city,
cluster,
machine,
random,
user
};
@throws Exception
*/
public static long[] parseId(long id) throws Exception {
long time=0;
long country=0;
long city=0;
long cluster=0;
long machine=0;
long random=0;
long user=0;
time = id >> (63 - 29) & 0x0000000001FFFFFFL;
country = id >> (63 - 32) & 0x0000000000000007L;
city = id >> (63 - 38) & 0x000000000000003FL;
cluster = id >> (63 - 40) & 0x0000000000000003L;
machine = id >> (63 - 46) & 0x000000000000003FL;
random = id >> (63 - 53) & 0x000000000000007FL;
user = id & 0x00000000000003FFL;
return new long[]{
time,
country,
city,
cluster,
machine,
random,
user
};
}
/
打印一个long的二进制码,不分割
@param l
@return
/
public static String pl64(long l){
return pl64(l,false);
}
/
打印一个long的二进制码
@param l 要打印的数值
@param split 是否每4位分割
@return
*/
public static String pl64(long l,boolean split){
StringBuilder sb = new StringBuilder();
for(int i=0;i<64;i++){
sb.append(pl(l, i));
if((i+1)%4 ==0 && split){
sb.append(“ “);
}
}
sb.append(“\r\n”);
return sb.toString();
}
/
打印l 的从0开始第index位的数据
@param l
@param index
/
public static String pl(long l,int index){
return (0x0000000000000001L & (l>> (63-index)))+””;
}
/
掩码创建工具,传递一个int数组,生成的掩码字符串会将该int中的位设置为1
例如System.out.println(createMask(63,62));,返回结果为0x0000000000000003L
@param cc
@return
*/
public static String createMask(int … cc){
StringBuilder sb = new StringBuilder();
for(int i=0;i< 64;i++){
String s_v = “0”;
for(int idx : cc){
if(idx == i){
s_v = “1”;
break;
}
}
sb.append(sv);
}
String str = sb.toString();
StringBuilder sb1= new StringBuilder();
sb1.append(“0x”);
for (int i=0;i<64;i+=4){
if(str.substring(i,i+4).equals(“0000”)){
sb1.append(“0”);
}else if(str.substring(i,i+4).equals(“0001”)){
sb1.append(“1”);
}else if(str.substring(i,i+4).equals(“0010”)){
sb1.append(“2”);
}else if(str.substring(i,i+4).equals(“0011”)){
sb1.append(“3”);
}else if(str.substring(i,i+4).equals(“0100”)){
sb1.append(“4”);
}else if(str.substring(i,i+4).equals(“0101”)){
sb1.append(“5”);
}else if(str.substring(i,i+4).equals(“0110”)){
sb1.append(“6”);
}else if(str.substring(i,i+4).equals(“0111”)){
sb1.append(“7”);
}else if(str.substring(i,i+4).equals(“1000”)){
sb1.append(“8”);
}else if(str.substring(i,i+4).equals(“1001”)){
sb1.append(“9”);
}else if(str.substring(i,i+4).equals(“1010”)){
sb1.append(“A”);
}else if(str.substring(i,i+4).equals(“1011”)){
sb1.append(“B”);
}else if(str.substring(i,i+4).equals(“1100”)){
sb1.append(“C”);
}else if(str.substring(i,i+4).equals(“1101”)){
sb1.append(“D”);
}else if(str.substring(i,i+4).equals(“1110”)){
sb1.append(“E”);
}else if(str.substring(i,i+4).equals(“1111”)){
sb1.append(“F”);
}
}
sb1.append(“L”);
return sb1.toString();
}
public static void main(String[] args) throws Exception {
//生成指定目标位的掩码
//System.out.println(createMask(54, 55, 56, 57, 58, 59, 60, 61, 62, 63));
//创建id示例
long id = createId(0, 0, 1, 3, 16, 33, 777);
System.out.println(id);
//将ID生成短可见ID
String strid = LongTransfer.getStrFrom(id);
System.out.println(strid);
//从短可见ID生成long
long id = LongTransfer.getLongFrom(strid);
System.out.println(id);
//对ID进行反向解析
System.out.println(“开始反向解析”);
for(long l : parseId(id)){
System.out.println(l);
}
//pl64(1);
//pl(1,63);
//System.out.println(createId(0,1,1,1,1,1,1,111));
//System.out.print(
// pl64(
// MASK_TIME | MASK_COUNTRY | MASK_CITY | MASK_CLUSTER | MASK_MACHINE | MASK_RANDOM | MASK_USER
// )
//);
}
}
——————————————————————————————————————————————————————————————————-
——————————————————————————-LongTransfer——————————————————————————————————
import java.util.Date;
public class LongTransfer {
/char 62 ,
用来处理62进制
/
private static char[] info = {
’0’,’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’,
’A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’,’J’,’K’,’L’,’M’,’N’,’O’,’P’,’Q’,’R’,’S’,’T’,’U’,’V’,’W’,’X’,’Y’,’Z’,
’a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’i’,’j’,’k’,’l’,’m’,’n’,’o’,’p’,’q’,’r’,’s’,’t’,’u’,’v’,’w’,’x’,’y’,’z’,
};
private static int jz = 62;
public static void main(String[] args) {
System.out.println(new Date(100,11,31));
//long long的最大值:9223372036854775807
//long long的最小值:-9223372036854775808
// System.out.println(getStrFrom(9223372036854775807l));//hezMo7
// System.out.println(getLongFrom(“aZl8N0y58M7”));
for(int i=0;i<10;i++){
long date = new Date(100,11,31).getTime();//获取1900+300 = 2200年的时间
date = date/1000;
String str = getStrFrom(date);
long result = getLongFrom(str);
System.out.print(date+” “);
System.out.print(str+” “);
System.out.print(result+” “);
System.out.println(“ “+(date==result?”true”:”false”));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static String getStrFrom(long l){
StringBuffer sb = new StringBuffer();
if(l==0)return “0”;
int jz = jz;
while(l/jz >= 0){
if(l==0){
//sb.insert(0, info[0]);
break;
}
char c = info[(int)(l%jz)];
//System.out.println((int)(l%62));
sb.insert(0, c);
l=l/jz;
}
return sb.toString();
}
public static long getLongFrom(String str){
long result = 0;
int jz = jz_;
int strlength = str.length();
char[] cc = new char[strlength];
str.getChars(0, strlength, cc, 0);
for(int i=0,j=strlength;i<j;i++ ){
int num = -1;
char c = cc[i];
if(‘0’<=c&&c<=’9’){
num = c-‘0’;
}
if(‘a’<=c&&c<=’z’){
num = c-‘a’+10;
}
if(‘A’<=c&&c<=’Z’){
num = c-‘A’+36;
}
//System.out.println(num);
result = result*jz + num;
}
return result;
}
}
——————————————————————————————————————————————————————————————————-