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 = timest
    //id由三部分组成
    return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
}

ID分三部分组成:

  1. (timestamp – twepoch) << timestampLeftShift
    当前毫秒时间戳 – 初始化毫秒时间戳 左移 22位

十进制:30149324525 = 1618584524525 – 1588435200000

转换二进制:11100000101000010100010111011101101

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

  1. 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

  1. 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/2488.html

阿飞技术的头像阿飞技术

相关推荐

关注我们
关注我们
购买服务
购买服务
返回顶部