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
7e7aa7cc
Commit
7e7aa7cc
authored
Apr 13, 2018
by
zhiguo.liu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
# 修改新发号器为使用时无需注入
parent
da4e5345
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
45 additions
and
52 deletions
+45
-52
IDGenerator.java
...src/main/java/cn/quantgroup/tech/util/id/IDGenerator.java
+45
-52
No files found.
commons-spring/src/main/java/cn/quantgroup/tech/util/id/IDGenerator.java
View file @
7e7aa7cc
...
...
@@ -27,7 +27,7 @@ import java.util.concurrent.TimeUnit;
* uid-generator 通过对 64 位数字分区来生成唯一 ID,由以下组成:
* <p>
* -----------------------------------------------------------------------------------
* | sign | delta seconds | worker id |
sequence
* | sign | delta seconds | worker id |
SEQUENCE
* -----------------------------------------------------------------------------------
* 1bits 28bits 22bits 13bits
* -----------------------------------------------------------------------------------
...
...
@@ -45,14 +45,14 @@ import java.util.concurrent.TimeUnit;
* 经测试,BigInteger 实现时,性能降低 60% 左右,每秒发号约为 100w~150w。
* 现在 uid 由以下组成
* ---------------------------------------------------------------------------------------------------------
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id |
sequence
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id |
SEQUENCE
* ---------------------------------------------------------------------------------------------------------
* 1bits 28bits 22bits 22bits 13bits
* ---------------------------------------------------------------------------------------------------------
* 其中 data center id + worker id +
sequence
设定的位数不大于 63。
* 其中 data center id + worker id +
SEQUENCE
设定的位数不大于 63。
* <p>
* 使用注意:
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id +
sequence
总数设定越大,号码位数越长
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id +
SEQUENCE
总数设定越大,号码位数越长
* 2. 各个分区的位数、起始时间一旦设定完成投入使用,则后续不能更改。否则会导致发号重复。
*
* @author zhiguo.liu
...
...
@@ -71,27 +71,27 @@ public class IDGenerator implements InitializingBean {
*/
@Value
(
"${id.dataCenterIdBits:0}"
)
protected
int
dataCenterIdBits
;
@Value
(
"${id.workerBits:8}"
)
protected
int
workerBits
;
@Value
(
"${id.seqBits:13}"
)
protected
int
seqBits
;
@Value
(
"${data.center.id}"
)
protected
long
dataCenterId
;
@Value
(
"${id.workerBits:8}"
)
protected
int
workerBits
;
protected
static
long
DATA_CENTER_ID
;
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
*/
protected
String
epochStr
;
pr
otected
long
epochSeconds
;
pr
ivate
static
long
EPOCH_SECONDS
;
/**
* Stable fields after spring bean initializing
*/
pr
otected
BitsAllocator
bitsAllocator
;
pr
otected
long
workerId
;
pr
ivate
static
BitsAllocator
ALLOCATOR
;
pr
ivate
static
long
WORKER_ID
;
/**
* Volatile fields caused by nextId()
*/
pr
otected
long
sequence
=
0L
;
pr
otected
long
lastSecond
=
-
1L
;
pr
ivate
static
long
SEQUENCE
=
0L
;
pr
ivate
static
long
LAST_SECOND
=
-
1L
;
/**
* Spring property
*/
...
...
@@ -102,18 +102,18 @@ public class IDGenerator implements InitializingBean {
public
void
afterPropertiesSet
()
throws
Exception
{
// initialize bits allocator
int
timeBits
=
64
-
1
-
dataCenterIdBits
-
workerBits
-
seqBits
;
bitsAllocator
=
new
BitsAllocator
(
timeBits
,
dataCenterIdBits
,
workerBits
,
seqBits
);
ALLOCATOR
=
new
BitsAllocator
(
timeBits
,
dataCenterIdBits
,
workerBits
,
seqBits
);
// initialize worker id
workerId
=
redisTemplate
.
opsForValue
().
increment
(
REDIS_WORK_ID_KEY
+
dataCenterId
,
1
)
%
bitsAllocator
.
getMaxWorkerId
();
Assert
.
isTrue
(
workerId
<
bitsAllocator
.
getMaxWorkerId
(),
"workerId
is too big"
);
Assert
.
isTrue
(
bitsAllocator
.
getMaxDataCenterId
()
!=
0
&&
dataCenterId
<
bitsAllocator
.
getMaxDataCenterId
(),
"dataCenterId
is too big"
);
WORKER_ID
=
redisTemplate
.
opsForValue
().
increment
(
REDIS_WORK_ID_KEY
+
DATA_CENTER_ID
,
1
)
%
ALLOCATOR
.
getMaxWorkerId
();
Assert
.
isTrue
(
WORKER_ID
<
ALLOCATOR
.
getMaxWorkerId
(),
"WORKER_ID
is too big"
);
Assert
.
isTrue
(
ALLOCATOR
.
getMaxDataCenterId
()
!=
0
&&
DATA_CENTER_ID
<
ALLOCATOR
.
getMaxDataCenterId
(),
"DATA_CENTER_ID
is too big"
);
LOGGER
.
info
(
"Initialized bits dataCenterBits:{}, workerBits:{}, seqBits:{}"
,
dataCenterIdBits
,
workerBits
,
seqBits
);
LOGGER
.
info
(
"Initialized nodes,
workerId:{}, dataCenterId:{}"
,
workerId
,
dataCenterId
);
LOGGER
.
info
(
"Initialized nodes,
WORKER_ID:{}, DATA_CENTER_ID:{}"
,
WORKER_ID
,
DATA_CENTER_ID
);
}
public
String
getID
(
String
pre
F
ix
)
throws
IDGenerateException
{
public
String
getID
(
String
pre
f
ix
)
throws
IDGenerateException
{
try
{
return
nextId
(
pre
F
ix
);
return
nextId
(
pre
f
ix
);
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"Generate unique id exception. "
,
e
);
throw
new
IDGenerateException
(
e
);
...
...
@@ -124,9 +124,9 @@ public class IDGenerator implements InitializingBean {
BigInteger
bigInteger
=
new
BigInteger
(
idStr
);
int
totalBits
=
bigInteger
.
bitLength
();
long
dataCenterIdBits
=
bitsAllocator
.
getDataCenterIdBits
();
long
workerIdBits
=
bitsAllocator
.
getWorkerIdBits
();
long
sequenceBits
=
bitsAllocator
.
getSequenceBits
();
long
dataCenterIdBits
=
ALLOCATOR
.
getDataCenterIdBits
();
long
workerIdBits
=
ALLOCATOR
.
getWorkerIdBits
();
long
sequenceBits
=
ALLOCATOR
.
getSequenceBits
();
if
(
totalBits
<
64
)
{
totalBits
=
64
;
long
id
=
bigInteger
.
longValue
();
...
...
@@ -137,9 +137,9 @@ public class IDGenerator implements InitializingBean {
dataCenterId
=
0
;
}
long
deltaSeconds
=
id
>>>
(
dataCenterIdBits
+
workerIdBits
+
sequenceBits
);
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
epochSeconds
+
deltaSeconds
));
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
EPOCH_SECONDS
+
deltaSeconds
));
String
thatTimeStr
=
DateFormatUtils
.
format
(
thatTime
,
DATETIME_PATTERN
);
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"
dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence
\":\"%d\"}"
,
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"
DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE
\":\"%d\"}"
,
id
,
thatTimeStr
,
dataCenterId
,
workerId
,
sequence
);
}
else
{
long
sequence
=
getBigIntegerFromLength
(
sequenceBits
).
and
(
bigInteger
).
longValue
();
...
...
@@ -149,9 +149,9 @@ public class IDGenerator implements InitializingBean {
dataCenterId
=
0
;
}
long
deltaSeconds
=
bigInteger
.
shiftRight
((
int
)
dataCenterIdBits
+
(
int
)
workerIdBits
+
(
int
)
sequenceBits
).
longValue
();
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
epochSeconds
+
deltaSeconds
));
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
EPOCH_SECONDS
+
deltaSeconds
));
String
thatTimeStr
=
DateFormatUtils
.
format
(
thatTime
,
DATETIME_PATTERN
);
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"
dataCenterId\":\"%d\",\"workerId\":\"%d\",\"sequence
\":\"%d\"}"
,
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"
DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE
\":\"%d\"}"
,
bigInteger
,
thatTimeStr
,
dataCenterId
,
workerId
,
sequence
);
}
}
...
...
@@ -170,29 +170,29 @@ public class IDGenerator implements InitializingBean {
long
currentSecond
=
getCurrentSecond
();
// Clock moved backwards, wait for newest time
if
(
currentSecond
<
lastSecond
)
{
getNextSecond
(
lastSecond
);
if
(
currentSecond
<
LAST_SECOND
)
{
getNextSecond
(
LAST_SECOND
);
}
// At the same second, increase
sequence
if
(
currentSecond
==
lastSecond
)
{
sequence
=
(
sequence
+
1
)
&
bitsAllocator
.
getMaxSequence
();
// Exceed the max
sequence
, we wait the next second to generate ID
if
(
sequence
==
0
)
{
currentSecond
=
getNextSecond
(
lastSecond
);
// At the same second, increase
SEQUENCE
if
(
currentSecond
==
LAST_SECOND
)
{
SEQUENCE
=
(
SEQUENCE
+
1
)
&
ALLOCATOR
.
getMaxSequence
();
// Exceed the max
SEQUENCE
, we wait the next second to generate ID
if
(
SEQUENCE
==
0
)
{
currentSecond
=
getNextSecond
(
LAST_SECOND
);
}
// At the different second,
sequence
restart from zero
// At the different second,
SEQUENCE
restart from zero
}
else
{
sequence
=
0L
;
SEQUENCE
=
0L
;
}
lastSecond
=
currentSecond
;
LAST_SECOND
=
currentSecond
;
// 当前时间小于设定的最大时间,即总位数在 64 位以下,用 long 生成数字
if
(
currentSecond
-
epochSeconds
<=
bitsAllocator
.
getMaxDeltaSeconds
())
{
return
preFix
+
bitsAllocator
.
allocate
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
if
(
currentSecond
-
EPOCH_SECONDS
<=
ALLOCATOR
.
getMaxDeltaSeconds
())
{
return
preFix
+
ALLOCATOR
.
allocate
(
currentSecond
-
EPOCH_SECONDS
,
DATA_CENTER_ID
,
WORKER_ID
,
SEQUENCE
);
}
return
preFix
+
bitsAllocator
.
allocateBigInteger
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
return
preFix
+
ALLOCATOR
.
allocateBigInteger
(
currentSecond
-
EPOCH_SECONDS
,
DATA_CENTER_ID
,
WORKER_ID
,
SEQUENCE
);
}
/**
...
...
@@ -214,16 +214,9 @@ public class IDGenerator implements InitializingBean {
return
TimeUnit
.
MILLISECONDS
.
toSeconds
(
System
.
currentTimeMillis
());
}
public
void
setWorkerBits
(
int
workerBits
)
{
if
(
workerBits
>
0
)
{
this
.
workerBits
=
workerBits
;
}
}
public
void
setSeqBits
(
int
seqBits
)
{
if
(
seqBits
>
0
)
{
this
.
seqBits
=
seqBits
;
}
@Value
(
"${data.center.id}"
)
public
void
setDataCenterId
(
Integer
dataCenterId
)
{
DATA_CENTER_ID
=
dataCenterId
;
}
@Value
(
"${id.epochStr:2018-04-01}"
)
...
...
@@ -231,7 +224,7 @@ public class IDGenerator implements InitializingBean {
if
(
StringUtils
.
isNotBlank
(
epochStr
))
{
this
.
epochStr
=
epochStr
;
try
{
this
.
epochSeconds
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
DateUtils
.
parseDate
(
epochStr
,
new
String
[]{
DAY_PATTERN
}).
getTime
());
EPOCH_SECONDS
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
DateUtils
.
parseDate
(
epochStr
,
new
String
[]{
DAY_PATTERN
}).
getTime
());
}
catch
(
ParseException
e
)
{
e
.
printStackTrace
();
}
...
...
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