baidu / uid-generator Goto Github PK
View Code? Open in Web Editor NEWUniqueID generator
License: Apache License 2.0
UniqueID generator
License: Apache License 2.0
项目地址 https://github.com/wujun234/uid-generator-spring-boot-starter ,已发布到maven**仓库。
基于 百度UidGenerator, 做了以下改动:
<dependency>
<groupId>com.github.wujun234</groupId>
<artifactId>uid-generator-spring-boot-starter</artifactId>
<version>1.0.2.RELEASE</version>
</dependency>
DROP TABLE IF EXISTS WORKER_NODE;
CREATE TABLE WORKER_NODE
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: CONTAINER(1), ACTUAL(2), FAKE(3)',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
CREATED TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(ID)
)
COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
//@Resource
//private UidGenerator defaultUidGenerator;
@Resource
private UidGenerator cachedUidGenerator;
@Test
public void testSerialGenerate() {
// Generate UID
long uid = cachedUidGenerator.getUID();
// Parse UID into [Timestamp, WorkerId, Sequence]
// {"UID":"450795408770","timestamp":"2019-02-20 14:55:39","workerId":"27","sequence":"2"}
System.out.println(cachedUidGenerator.parseUID(uid));
}
uidGenerator-timeBits: 23
uidGenerator-workerBits: 31
uidGenerator-seqBits: 9
uidGenerator-epochStr: '2018-12-22'
uidGenerator-boostPower: 3
uidGenerator-paddingFactor: 50
uidGenerator-scheduleInterval: 60
当参数为这些时会出现负数
基于现有设计,如果时间回退了,会造成ID重复吗
UID-RingBuffer不需要吗?
默认实现的是重启拿取新的workerid的方式,我觉得这块可以优化。可以基于唯一不变性约束来减少workerid的消耗,比如拿机器mac+机器ip地址作为唯一的方式来确定workerid,通过mysql insert on duplicate update模式,如果该唯一的标识(mac+ip)不存在则插入成功,得到新的workerid,如果已经存在,则获取原有的id信息,这样可以减少workerid的消耗,那么workerid的位数就可以不需要那么多位,比如可能只需要15bit,就可以实现32768台机器的部署规模,将更多的位数留给timeBits和seqBits,提高使用年限和并发度,同时可以引入heartbeat心跳,对于一些下架的机器根据失效的心跳从worker表中踢除,以节约更多的机器。
以上是我个人的见解,并根据以上思路实现了一个ReusableWorkerIdAssigner,如有不对的地方,请指正。如果可以,我也可以提一个PR。
序号 2的9次方 = 512
workid数 2的23次方 = 8388608
重启次数 68 乘上 365 乘上 12 天 = 297840
应用数 节点 除以 重启次数 = 8388608 / 297840 = 28
并发 28 乘上 512 = 14336
这个算的思路是对的吗?
因为disruptor的RingBuffer是会有重复消费问题的,请问uid-generator使用了RingBuffer是如何解决重复消费问题的,谢谢
本身id的生成是纯内存操作,靠移位就可以完成。buffer的意义个人感觉不大,而且put和take的时候做很多异步操作更是对cpu的一种浪费。
求问CachedUidGenerator的意义何在呢??
spring boot + jpa
你好,
查看了下源代码,应该是spring基于XML通过set方式进行bean实例化。但类“CachedUidGenerator”中的成员变量“paddingFactor”没有set方法:setPaddingFactor()。不晓得我理解的对不对?
对比了原生的snowflake和DefaultUidGenerator的性能,在同样的测试环境下:
消耗时间对比:
是什么导致两者差距这么明显呢?分析代码后,怀疑是DefaultUidGenerator的getNextSecond()方法阻塞了请求导致性能的急剧下降。因为DefaultUidGenerator是按秒为单位去阻塞的,而原生的snowflake是按毫秒阻塞的。对比两者的阻塞次数:
从中分析可以得知,DefaultUidGenerator的getNextSecond()方法确实是造成性能急剧下降的罪魁祸首,因为在10万次id生成的过程中,阻塞了24次,尽管每次不一定到1秒(取决于该秒内序列号被使用完时距离1秒结束的时间差),但是结论应该是显而易见的。
为了验证这个结论,我将DefaultUidGenerator改成毫秒级别,重新测试DefaultUidGenerator.testSerialGenerate(),消耗时间降到了:38ms。
所以,毫秒级序列号的设计比秒级序列号设计性能要高得多。
如题
是否可以提供maven引入方式
UidGenerator 这个东西很好,什么时间升级一下,让我们好集成Springboot?
我的测试数据如下:
JMH 1.17.5 (released 249 days ago, please consider updating!)
VM version: JDK 1.8.0_101, VM 25.101-b13
VM invoker: D:\apps\jdk\jdk1.8.0_101\jre\bin\java.exe
VM options: -Didea.launcher.port=7537 -Didea.launcher.bin.path=D:\apps\JetBrains\IntelliJ IDEA 2016.3.1\bin -Dfile.encoding=UTF-8
Warmup: 5 iterations, 5 s each
Measurement: 20 iterations, 5 s each
Timeout: 10 min per iteration
Threads: 20 threads, will synchronize iterations
Benchmark mode: Throughput, ops/time
Benchmark: com.vpal.beifu.customs.benchmarktest.IdGeneratorBenchmarkTest.benchPrecondition
Run progress: 0.00% complete, ETA 00:02:05
Fork: 1 of 1
Warmup Iteration
Warmup Iteration 2: 91892.284 ops/s
Warmup Iteration 3: 91975.161 ops/s
Warmup Iteration 4: 92341.250 ops/s
Warmup Iteration 5: 99186.817 ops/s
Iteration 1: 90499.371 ops/s
Iteration 2: 86129.521 ops/s
Iteration 3: 75192.984 ops/s
Iteration 4: 78517.215 ops/s
Iteration 5: 78064.527 ops/s
Iteration 6: 78340.945 ops/s
Iteration 7: 75036.587 ops/s
Iteration 8: 77089.315 ops/s
Iteration 9: 78202.288 ops/s
Iteration 10: 75584.124 ops/s
Iteration 11: 74410.960 ops/s
Iteration 12: 76744.887 ops/s
Iteration 13: 74803.554 ops/s
Iteration 14: 75628.749 ops/s
Iteration 15: 74925.918 ops/s
Iteration 16: 76541.028 ops/s
Iteration 17: 77475.313 ops/s
Iteration 18: 75880.433 ops/s
Iteration 19: 77597.357 ops/s
Iteration 20: 75894.316 ops/s
Result "com.vpal.beifu.customs.benchmarktest.IdGeneratorBenchmarkTest.benchPrecondition":
77627.970 ±(99.9%) 3419.012 ops/s [Average]
(min, avg, max) = (74410.960, 77627.970, 90499.371), stdev = 3937.339
CI (99.9%): [74208.958, 81046.981] (assumes normal distribution)
Run complete. Total time: 00:02:09
Benchmark Mode Cnt Score Error Units
IdGeneratorBenchmarkTest.benchPrecondition thrpt 20 77627.970 ± 3419.012 ops/s
作者你好!最近在下正在试图阅读理解源码,对calSlotIndex的计算方式有些疑惑:
/**
* Calculate slot index with the slot sequence (sequence % bufferSize)
*/
protected int calSlotIndex(long sequence) {
return (int) (sequence & indexMask);
}
如此计算出的nextIndex将是不序列递增且极易连续重复的,怎么能用于slots[nextIndex]取uid呢?
delta seconds (28 bits) 当前时间,相对于时间基点"2016-05-20"的增量值,单位:秒,最多可支持约8.7年
怎么计算得到的8.7年
目前CachedUidGenerator在初始化的时候lastSecond用的是当前秒,后续的只是在此基础上+1(不在依赖时钟,并发高的时候还可以预借),不过如果ID生成很少,那么就可能导致生成的ID(解析后)于实际的时间相差很多。
虽然ID相对有序,但是有些时候还是需要根据ID大致知道相应的时间。目前这样ID里面的时间就不需要很准确。
比如在schedule周期性调整lastSecond,或者其他方法。
Hi,
I follow the guide to setup this project and it works. I can have different config in "application-dev.properties" for development environment and other files for other environment. But how can I config multiple environment for "uid/mysql.properties" file? Thanks!
the line 'due to the CUP cache mechanism'
CUP ->CPU? 😊
如题
When Step 2: Create table WORKER_NODE, Invalid default value for 'CREATED' issures
CURRENT_TIMESTAMP is only acceptable on TIMESTAMP fields. DATETIME fields must be left either with a null default value, or no default value at all - default values must be a constant value, not the result of an expression.
relevant docs:
http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html
UidGenerator 生成id 重复的问题
在对部署在多台docker里面的项目进行压测的时候,使用UidGenerator 省的的id 会出现重复的问题,网上找了,好久 好像大家都没有这方面的问题,为啥就我会出现呢 ~~~~
请问有其他人遇到过吗? 是怎么解决的
请问fsg 是什么的简称
/**
* Calculate slot index with the slot sequence (sequence % bufferSize)
*/
protected int calSlotIndex(long sequence) {
return (int) (sequence & indexMask);
}
将生成的UID作为ID存储在mysql,是否会出现溢出
uid-generator Hibernate 怎么配置
看了看代码 网上也找了找资料, 愣是没找到集群的使用方法. 集群下可以不重复 并且有序吗
It is time-consuming for currentTimeMillis ===> seconds
long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
under method getCurrentSecond().
After i change to currentTimeMillis instead of transferring to seconds,
It is much faster. Otherwise DefaultUidGenerator is very slow.
如题
是否解决了时钟回拨的问题
在服务器启动时,类BufferPaddingExecutor构造函数对lastSecond进行初始化赋值,之后不再采用系统时间尽心校准,进而避免了时钟回调问题。我不太理解为什么要采用双buffer设计,既然lastSecond是稳定的lastSecond.incrementAndGet()进行递增,在每秒内的sequence(默认seqBits为13)也可以在0和8191间递增,那么此时采用双Buffer的意义是什么呢?
你好,问下一个应用使用多个数据源并且一个数据源会被多个应用使用,这样多对多的情况下要怎么配置
数据库是干什么用的
时间单位是秒,也就是每秒产生8192个id
怎么实现单机600万的性能呢?
感谢百度开源了本项目,鄙人在研读源码的时候有点疑惑,希望能得到各位前辈的指点。
在RingBuffer
内有两个环形数组,一个名为slots作用为存储UID,另一个名为flags用于存储标志位。
具体引用代码如下
slots中的元素唯一被填充的填充的地方是com.baidu.fsg.uid.buffer.RingBuffer#put
,并通过线程池间接调用了该方法,多线程间对slots进行写操作在多核处理器下应该也会使得该数组发生伪共享问题,请问为什么不像flags一样地去使用PaddedAtomicLong进行补齐,或者是我对伪共享有错误的理解,望不吝赐教!
既然有tail、cursor分别表示生产,消费的offset,直接根据这个两个变量确定put, take的位置不就好了吗?为什么还需要Flag-RingBuffer,以及判断里面相应位置的状态?
@baozhi 咨询个性能问题啊
本地压测通过http获取id时,有几次耗时超过300ms(还有超过1s的),这个不是在内存连续存储的么,怎么还这么慢?
是一遍获取id,一点存储id导致?
配置:
CachedUidGenerator、boostPower=7
-Xms12G -Xmx12G
server.tomcat.max-threads=1000
jemeter 500线程,吞吐量9K左右
时间只占用28位,只能要8年,机器id占22位,有朋友能解释下为什么吗?
因我不具有groupid:com.baidu. 的deploy角色,请将本项目的jar部署到官方仓库,造福广大javaer,感谢!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.