Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
commons
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
3
Merge Requests
3
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DevOps
commons
Commits
fd0d7354
Commit
fd0d7354
authored
Mar 06, 2018
by
zhiguo.liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 新发号器添加详细说明
parent
e745ae77
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
45 additions
and
29 deletions
+45
-29
DefaultUidGenerator.java
.../java/cn/quantgroup/tech/util/id/DefaultUidGenerator.java
+40
-25
DisposableWorkerIdAssigner.java
...n/quantgroup/tech/util/id/DisposableWorkerIdAssigner.java
+5
-4
No files found.
commons-spring/src/main/java/cn/quantgroup/tech/util/id/DefaultUidGenerator.java
View file @
fd0d7354
...
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
...
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.Assert
;
import
org.springframework.util.Assert
;
...
@@ -18,36 +19,49 @@ import java.util.concurrent.TimeUnit;
...
@@ -18,36 +19,49 @@ import java.util.concurrent.TimeUnit;
/**
/**
* Represents an implementation of {@link UidGenerator}
* Represents an implementation of {@link UidGenerator}
* <p>
* 基于百度开源项目 uid-generator 的增强版,Snowflake Java 实现版本。项目 Github:https://github.com/baidu/uid-generator
* The unique id has 64bits (long), default allocated as blow:<br>
* <li>sign: The highest bit is 0
* <li>delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000).
* Supports about 8.7 years until to 2024-11-20 21:24:16
* <li>worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W
* <li>sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s<br><br>
* <p>
* <p>
* <pre>{@code
* +------+----------------------+----------------+-----------+
* | sign | delta seconds | worker node id | sequence |
* +------+----------------------+----------------+-----------+
* 1bit 28bits 22bits 13bits
* }</pre>
* <p>
* You can also specified the bits by Spring property setting.
* <li>timeBits: default as 28
* <li>workerBits: default as 22
* <li>seqBits: default as 13
* <li>epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'<p>
* <p>
* <b>Note that:</b> The total bits must be 64 -1
*
*
* @author yutianbao
* uid-generator 通过对 64 位数字分区来生成唯一 ID,由以下组成:
*
* -----------------------------------------------------------------------------------
* | sign | delta seconds | worker id | sequence
* -----------------------------------------------------------------------------------
* 1bits 28bits 22bits 13bits
* -----------------------------------------------------------------------------------
* 其中 delta seconds 为 当前时间 - 指定起始时间。
* 该版本有三个问题
* 1. delta seconds 位数有限,28bits 也只能允许运行 8.7 年左右。
* 2. worker id 生成号码为用后即弃,可容纳重启次数有限。
* 3. 微服务分布式的情况下,无法使用统一数据源,则不同服务生成 worker id 时会重复
*
* 于是做出以下改进
* 1. worker id 拆分成 data center id,每个服务通过约定指定自己的 data center id 。
* 2. worker id 通过 redis 自增指定,设计为首尾相连的环形,自增数字达到设定的最大值时,会从0开始。
* 2. 不限制使用 delta seconds 的位数,则实现了无限时间的使用。当位数增长到 64 为后,改用 BigInteger 的位运算实现。
*
* 经测试,BigInteger 实现时,性能降低 60% 左右,每秒发号约为 100w~150w。
* 现在 uid 由以下组成
* ---------------------------------------------------------------------------------------------------------
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id | sequence
* ---------------------------------------------------------------------------------------------------------
* 1bits 28bits 22bits 22bits 13bits
* ---------------------------------------------------------------------------------------------------------
* 其中 data center id + worker id + sequence 设定的位数不大于 63。
*
* 使用注意:
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id + sequence 总数设定越大,号码位数越长
* 2. 各个分区的位数、起始时间一旦设定完成投入使用,则后续不能更改。否则会导致发号重复。
*
*
*
* @author zhiguo.liu
*/
*/
@Component
@Component
@ConditionalOnProperty
(
name
=
"data.center.id"
)
public
class
DefaultUidGenerator
implements
UidGenerator
,
InitializingBean
{
public
class
DefaultUidGenerator
implements
UidGenerator
,
InitializingBean
{
public
static
final
String
DATETIME_PATTERN
=
"yyyy-MM-dd HH:mm:ss"
;
public
static
final
String
DATETIME_PATTERN
=
"yyyy-MM-dd HH:mm:ss"
;
public
static
final
String
DAY_PATTERN
=
"yyyy-MM-dd"
;
public
static
final
String
DAY_PATTERN
=
"yyyy-MM-dd"
;
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
DefaultUidGenerator
.
class
);
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
DefaultUidGenerator
.
class
);
/**
/**
* Bits allocate
* Bits allocate
...
@@ -60,6 +74,8 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
...
@@ -60,6 +74,8 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
protected
int
workerBits
;
protected
int
workerBits
;
@Value
(
"${uid.seqBits:13}"
)
@Value
(
"${uid.seqBits:13}"
)
protected
int
seqBits
;
protected
int
seqBits
;
@Value
(
"${data.center.id}"
)
protected
long
dataCenterId
;
/**
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
...
@@ -72,7 +88,6 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
...
@@ -72,7 +88,6 @@ public class DefaultUidGenerator implements UidGenerator, InitializingBean {
*/
*/
protected
BitsAllocator
bitsAllocator
;
protected
BitsAllocator
bitsAllocator
;
protected
long
workerId
;
protected
long
workerId
;
protected
long
dataCenterId
;
/**
/**
* Volatile fields caused by nextId()
* Volatile fields caused by nextId()
...
...
commons-spring/src/main/java/cn/quantgroup/tech/util/id/DisposableWorkerIdAssigner.java
View file @
fd0d7354
...
@@ -18,10 +18,13 @@ package cn.quantgroup.tech.util.id;
...
@@ -18,10 +18,13 @@ package cn.quantgroup.tech.util.id;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
@Component
@Component
@ConditionalOnClass
(
RedisTemplate
.
class
)
public
class
DisposableWorkerIdAssigner
{
public
class
DisposableWorkerIdAssigner
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
DisposableWorkerIdAssigner
.
class
);
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
DisposableWorkerIdAssigner
.
class
);
private
static
final
String
REDIS_WORK_ID_KEY
=
"GLOBAL:WORK:ID:"
;
private
static
final
String
REDIS_WORK_ID_KEY
=
"GLOBAL:WORK:ID:"
;
...
@@ -30,10 +33,8 @@ public class DisposableWorkerIdAssigner {
...
@@ -30,10 +33,8 @@ public class DisposableWorkerIdAssigner {
private
StringRedisTemplate
redisTemplate
;
private
StringRedisTemplate
redisTemplate
;
/**
/**
* Assign worker id base on database.<p>
* Assign worker id base on Redis.<p>
* If there is host name & port in the environment, we considered that the node runs in Docker container<br>
* 使用 Redis 的 incr 命令,最后结果为 incr % maxWorkerId
* Otherwise, the node runs on an actual machine.
*
* @param dataCenterId
* @param dataCenterId
* @param bitsAllocator
* @param bitsAllocator
* @return assigned worker id
* @return assigned worker id
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment