您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    了解Snowflake算法的完成原理(3)
    时间:2020-08-10 21:30 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

      左移5位             11111111 11111111 11111111 11111111 11111111 11111111 11111111 11100000 

      [-1] 的补码         11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 

      异或                ----------------------------------------------------------------------- ^  

      结果的补码          00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011111  (十进制数 2^0 + 2^1 + 2^2 + 2^3 + 2^4 = 31) 

    这样就能计算出 5 bit 能表示的最大数值 n , n 为整数并且 0 <= n <= 31 ,即 0、1、2、3...31 。 Worker ID 和 Data Center ID 部分的最大值就是运用这种组合运算得出的。

    用固定位的最大值作为Mask避免溢出:

    Snowflake 算法中有这样的代码:

    var sequence = 0L 

    ...... 

    private val sequenceBits = 12L 

    // 这里失掉的是sequence的最大值4095 

    private val sequenceMask = -1L ^ (-1L << sequenceBits) 

    ...... 

    sequence = (sequence + 1) & sequenceMask 

    最后这个算子其实就是 sequence = (sequence + 1) & 4095 ,假定 sequence 以后值为 4095 ,推演一下计算进程:

    * [4095] 的补码                 00000000 00000000 00000000 00000000 00000000 00000000 00000111 11111111 

      [sequence + 1] 的补码         00000000 00000000 00000000 00000000 00000000 00000000 00001000 00000000 

      按位与                        ----------------------------------------------------------------------- & 

      计算结果                      00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000  (十进制数:0) 

    可以编写一个 main 办法验证一下:

    public static void main(String[] args) { 

        int mask = 4095; 

        System.out.println(0 & mask); // 0 

        System.out.println(1 & mask); // 1 

        System.out.println(2 & mask); // 2 

        System.out.println(4095 & mask); // 4095 

        System.out.println(4096 & mask); // 0 

        System.out.println(4097 & mask); // 1 

    也就是 x = (x + 1) & (-1L ^ (-1L << N)) 能保证最终失掉的 x 值不会超过 N ,这是应用了按位与中的"取指定位"的特性。

    Snowflake算法完成源码剖析

    Snowflake 虽然用 Scala 言语编写,语法其实和 Java 差不多,当成 Java 代码这样阅读就行,下面阅读代码的时分会跳过一些日志记载和度量统计的逻辑。先看 IdWorker.scala 的属性值:

    // 定义基准纪元值,这个值是北京时间2010-11-04 09:42:54,估量就是2010年终版提交代码时分定义的一个时间戳 

    val twepoch = 1288834974657L 

     

    // 初始化序列号为0 

    (责任编辑:admin)