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

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值