分布式系统一致性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;

    }

}



——————————————————————————————————————————————————————————————————-