Seata 分布式ID 雪花算法

Seata源码解析

Seata-common模块,IdWorker类分析

运算符知识:

  • 与运算  &  两位同时为1,结果为1,否则为0
  • 或运算   |  参加运算的两个对象只要有一个为1,其值为1
  • 异或运算   ^  参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0
  • 取反运算   ~  对一个二进制数按位取反,即将0变1,1变0

ID生成器,雪花算法

private final long workerIdShift = 12;private final long twepoch = 1588435200000L;private final long timestampLeftShift = 22;
public synchronized long nextId() { //获取当前毫秒数 long timestamp = timeGen();
if (timestamp < lastTimestamp) { throw new RuntimeException(String.format( "clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); }
if (lastTimestamp == timestamp) { //每一毫秒获取不超过4095个id, 超过在下一毫秒获取 sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; //id由三部分组成 return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence; }

ID分三部分组成:

1. (timestamp – twepoch) << timestampLeftShift

        当前毫秒时间戳  –  初始化毫秒时间戳    左移 22位

十进制:30149324525 = 1618584524525 – 1588435200000

转换二进制:11100000101000010100010111011101101

左移22位(补22个0):111000001010000101000101110111011010000000000000000000000

2. workerId << workerIdShift  获取机器id 左移12位

public static final int SIZE = 8;
public static long initWorkerId() { InetAddress address; try { address = InetAddress.getLocalHost(); } catch (final UnknownHostException e) { throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!",e); } byte[] ipAddressByteArray = address.getAddress(); //机器id由两值相加 return ((ipAddressByteArray[ipAddressByteArray.length - 2] & 0B11) << Byte.SIZE) + (ipAddressByteArray[ipAddressByteArray.length - 1] & 0xFF); }

ipAddressByteArray 返回本机ip4或ip6字节数组;

0B对应二进制,0x对应十六进制

机器id由两值相加: 

  •  (byte值 & 0B11) << Byte.SIZE;即最大值为 0B11=3,   左移8位:1100000000;   所以最大十进制值:768
  •  (byte值 & 0xFF) ; 16进制F对应二进制为 1111,所以最大十进制值:255

768 + 255 = 1023,也就是机器id最大不超过1023

workerId << workerIdShift  即:1111111111000000000000

3. sequence

sequence = (sequence + 1) & sequenceMask;

long sequenceMask = -1L ^ (-1L << 12L) 左移12位:

负数用正值的补码形式表达;原码取反变反码,反码加1变成补码

最终二进制为 111111111111,十进制为4095,sequence 最大为4095,否则获取下一个毫秒数,从0开始计算 

最终二进制位标识:111000001001101110001011110111010100000000000000000000000   |   1111111111000000000000  |  111111111111

位结构:前41位-时间戳   中间10位-机器id   后12位-自增id

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/221961.html

联系我们
联系我们
分享本页
返回顶部