635 Star 2.6K Fork 782

柠檬夕桐 / sequence

 / 详情

代码生成小问题,第一次生成ID尾数必定为偶数或0.

Done
Opened this issue  
2017-05-08 16:51

导致在实际应用的生成数值为如下
输入图片说明

Comments (10)

聂秋秋 created 任务

@柠檬夕桐 入库的数据大量偶数,不利于取余分表

@juapk 没有发现大量偶数呀
输入图片说明

@柠檬夕桐 如上问题截图,id 生成需要休眠一会、会重现

@juapk 实际场景也是大批量的休眠生成?

柠檬夕桐 added label question

@juapk 该算法的序列包括四部分:

1bit校验位+41bit的毫秒级时间戳位+10bit机器ID位+12bit序列位

在相同的毫秒时间戳时刻,最多可以产生4096个有序序列号。所以非休眠的情况,产生的序列号则会有多个值,但你所描述的场景中是做了一定的休眠的,所以说41位的毫秒级时间戳位已经不同,基本可以认为你所产生的所有序列都是不同毫秒级时间戳的,因此其相对的序列位都只是第一个序列值(即0),所以进行转换后基本都是偶数了。

这是没办法解决,或者说该序列不适合用来解决该场景的问题

@柠檬夕桐 现实肯定休眠不会跟测试用例一样不停地再生产ID,该问题已经有解决方案,并解决了(不一定是最佳方案),这里反馈给你是希望帮助你完善

改成下面的试试。

// 如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
    long old = sequence;
    sequence = (sequence + 1) & sequenceMask;
    // 毫秒内序列溢出
    if (sequence == old) {
        // 阻塞到下一个毫秒,获得新的时间戳
        timestamp = tilNextMillis(lastTimestamp);
    }
} else {// 时间戳改变,毫秒内序列重置
    sequence = ThreadLocalRandom.current().nextLong(0,2);
}

兄弟我看差了,毫秒内序列溢出应该还是if (sequence == 0),你这个nextId方法是同步的估计很难达到一毫秒内超过4095个序列号,所以这个if基本不会走。

聂秋秋 closed 任务

@juapk 对于吞吐量不是很大的应用是会遇到偶数分布占比扩大的情况。这个是雪花算法的特性决定的,所以常规的id hash分表的策略在此并不合适,原因很简单,数据分布不均匀。因此需要结合你们的业务特性做流水号定制化,比如融入一些基因特质。

@聂秋秋 提供了一种解决办法,牺牲毫秒内的绝对递增时间戳
测试代码

Sign in to comment

Status
Assignees
Milestones
Pull Requests
Successfully merging a pull request will close this issue.
Branches
Planed to start   -   Planed to end
-
Top level
Priority
参与者(5)
12260 jobob 1578914833 78621 yu120 1634033495 399953 nieqiurong 1578922708
Java
1
https://git.oschina.net/yu120/sequence.git
git@git.oschina.net:yu120/sequence.git
yu120
sequence
sequence

Search