Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
程序猿小郑
microservices-platform
提交
c55b3c0f
microservices-platform
项目概览
程序猿小郑
/
microservices-platform
与 Fork 源项目一致
Fork自
zlt2000 / microservices-platform
通知
4
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
microservices-platform
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
c55b3c0f
编写于
3月 06, 2019
作者:
zlt2000
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加分布式id生成器
上级
d5de392d
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
230 addition
and
56 deletion
+230
-56
README.md
README.md
+3
-3
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/IdGenerator.java
...r/src/main/java/com/central/common/utils/IdGenerator.java
+23
-0
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/Sequence.java
...rter/src/main/java/com/central/common/utils/Sequence.java
+204
-0
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/UUIDUtil.java
...rter/src/main/java/com/central/common/utils/UUIDUtil.java
+0
-53
未找到文件。
README.md
浏览文件 @
c55b3c0f
...
...
@@ -31,7 +31,7 @@
## 2. 项目总体架构图
![](
https://gitee.com/zlt2000/images/raw/master/spring
cloud
微服务架构图.jpg)
![](
https://gitee.com/zlt2000/images/raw/master/spring
cloud
微服务架构图.jpg
)
...
...
@@ -54,12 +54,12 @@
*
分布式锁
*
分布式任务调度器
*
支持CI/CD持续集成(包括前端和后端)
*
分布式高性能Id生成器
*
**系统监控功能**
*
服务调用链监控
*
应用拓扑图
*
慢服务检测
*
服务Metric监控
*
应用监控(应用健康、JVM、内存、线程)
*
错误日志查询
*
慢查询SQL监控
...
...
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/IdGenerator.java
0 → 100644
浏览文件 @
c55b3c0f
package
com.central.common.utils
;
/**
* 高效分布式ID生成算法(sequence),基于Snowflake算法优化实现64位自增ID算法。
* 其中解决时间回拨问题的优化方案如下:
* 1. 如果发现当前时间少于上次生成id的时间(时间回拨),着计算回拨的时间差
* 2. 如果时间差(offset)小于等于5ms,着等待 offset * 2 的时间再生成
* 3. 如果offset大于5,则直接抛出异常
*
* @author zlt
* @date 2019/3/5
*/
public
class
IdGenerator
{
private
static
Sequence
WORKER
=
new
Sequence
();
public
static
long
getId
()
{
return
WORKER
.
nextId
();
}
public
static
String
getIdStr
()
{
return
String
.
valueOf
(
WORKER
.
nextId
());
}
}
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/Sequence.java
0 → 100644
浏览文件 @
c55b3c0f
package
com.central.common.utils
;
import
cn.hutool.core.date.SystemClock
;
import
cn.hutool.core.lang.Assert
;
import
cn.hutool.core.util.StrUtil
;
import
com.baomidou.mybatisplus.core.toolkit.StringPool
;
import
lombok.extern.slf4j.Slf4j
;
import
java.lang.management.ManagementFactory
;
import
java.net.InetAddress
;
import
java.net.NetworkInterface
;
import
java.util.concurrent.ThreadLocalRandom
;
/**
* 分布式高效有序ID生成器
* 优化开源项目:http://git.oschina.net/yu120/sequence
*
* Twitter_Snowflake<br>
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 -
* 000000000000 <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T
* = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
*
* @author zlt
* @date 2019/3/5
*/
@Slf4j
public
class
Sequence
{
/**
* 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
*/
private
final
long
twepoch
=
1288834974657L
;
/**
* 机器标识位数
*/
private
final
long
workerIdBits
=
5L
;
private
final
long
datacenterIdBits
=
5L
;
private
final
long
maxWorkerId
=
-
1L
^
(-
1L
<<
workerIdBits
);
private
final
long
maxDatacenterId
=
-
1L
^
(-
1L
<<
datacenterIdBits
);
/**
* 毫秒内自增位
*/
private
final
long
sequenceBits
=
12L
;
private
final
long
workerIdShift
=
sequenceBits
;
private
final
long
datacenterIdShift
=
sequenceBits
+
workerIdBits
;
/**
* 时间戳左移动位
*/
private
final
long
timestampLeftShift
=
sequenceBits
+
workerIdBits
+
datacenterIdBits
;
private
final
long
sequenceMask
=
-
1L
^
(-
1L
<<
sequenceBits
);
private
final
long
workerId
;
/**
* 数据标识 ID 部分
*/
private
final
long
datacenterId
;
/**
* 并发控制
*/
private
long
sequence
=
0L
;
/**
* 上次生产 ID 时间戳
*/
private
long
lastTimestamp
=
-
1L
;
/**
* 时间回拨最长时间(ms),超过这个时间就抛出异常
*/
private
long
timestampOffset
=
5L
;
public
Sequence
()
{
this
.
datacenterId
=
getDatacenterId
(
maxDatacenterId
);
this
.
workerId
=
getMaxWorkerId
(
datacenterId
,
maxWorkerId
);
}
/**
* <p>
* 有参构造器
* </p>
*
* @param workerId 工作机器 ID
* @param datacenterId 序列号
*/
public
Sequence
(
long
workerId
,
long
datacenterId
)
{
Assert
.
isFalse
(
workerId
>
maxWorkerId
||
workerId
<
0
,
String
.
format
(
"worker Id can't be greater than %d or less than 0"
,
maxWorkerId
));
Assert
.
isFalse
(
datacenterId
>
maxDatacenterId
||
datacenterId
<
0
,
String
.
format
(
"datacenter Id can't be greater than %d or less than 0"
,
maxDatacenterId
));
this
.
workerId
=
workerId
;
this
.
datacenterId
=
datacenterId
;
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected
static
long
getMaxWorkerId
(
long
datacenterId
,
long
maxWorkerId
)
{
StringBuilder
mpid
=
new
StringBuilder
();
mpid
.
append
(
datacenterId
);
String
name
=
ManagementFactory
.
getRuntimeMXBean
().
getName
();
if
(
StrUtil
.
isNotEmpty
(
name
))
{
/*
* GET jvmPid
*/
mpid
.
append
(
name
.
split
(
StringPool
.
AT
)[
0
]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return
(
mpid
.
toString
().
hashCode
()
&
0xffff
)
%
(
maxWorkerId
+
1
);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected
static
long
getDatacenterId
(
long
maxDatacenterId
)
{
long
id
=
0L
;
try
{
InetAddress
ip
=
InetAddress
.
getLocalHost
();
NetworkInterface
network
=
NetworkInterface
.
getByInetAddress
(
ip
);
if
(
network
==
null
)
{
id
=
1L
;
}
else
{
byte
[]
mac
=
network
.
getHardwareAddress
();
if
(
null
!=
mac
)
{
id
=
((
0x000000FF
&
(
long
)
mac
[
mac
.
length
-
1
])
|
(
0x0000FF00
&
(((
long
)
mac
[
mac
.
length
-
2
])
<<
8
)))
>>
6
;
id
=
id
%
(
maxDatacenterId
+
1
);
}
}
}
catch
(
Exception
e
)
{
log
.
warn
(
" getDatacenterId: "
+
e
.
getMessage
());
}
return
id
;
}
/**
* 获取下一个ID
*
* @return
*/
public
synchronized
long
nextId
()
{
long
timestamp
=
timeGen
();
//闰秒
if
(
timestamp
<
lastTimestamp
)
{
long
offset
=
lastTimestamp
-
timestamp
;
if
(
offset
<=
timestampOffset
)
{
try
{
wait
(
offset
<<
1
);
timestamp
=
timeGen
();
if
(
timestamp
<
lastTimestamp
)
{
throw
new
RuntimeException
(
String
.
format
(
"Clock moved backwards. Refusing to generate id for %d milliseconds"
,
offset
));
}
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
e
);
}
}
else
{
throw
new
RuntimeException
(
String
.
format
(
"Clock moved backwards. Refusing to generate id for %d milliseconds"
,
offset
));
}
}
if
(
lastTimestamp
==
timestamp
)
{
// 相同毫秒内,序列号自增
sequence
=
(
sequence
+
1
)
&
sequenceMask
;
if
(
sequence
==
0
)
{
// 同一毫秒的序列数已经达到最大
timestamp
=
tilNextMillis
(
lastTimestamp
);
}
}
else
{
// 不同毫秒内,序列号置为 1 - 3 随机数
sequence
=
ThreadLocalRandom
.
current
().
nextLong
(
1
,
3
);
}
lastTimestamp
=
timestamp
;
// 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分
return
((
timestamp
-
twepoch
)
<<
timestampLeftShift
)
|
(
datacenterId
<<
datacenterIdShift
)
|
(
workerId
<<
workerIdShift
)
|
sequence
;
}
protected
long
tilNextMillis
(
long
lastTimestamp
)
{
long
timestamp
=
timeGen
();
while
(
timestamp
<=
lastTimestamp
)
{
timestamp
=
timeGen
();
}
return
timestamp
;
}
protected
long
timeGen
()
{
return
SystemClock
.
now
();
}
}
zlt-commons/zlt-common-spring-boot-starter/src/main/java/com/central/common/utils/UUIDUtil.java
已删除
100644 → 0
浏览文件 @
d5de392d
package
com.central.common.utils
;
import
java.util.UUID
;
/**
* 短8位UUID思想其实借鉴微博短域名的生成方式,但是其重复概率过高,而且每次生成4个,需要随即选取一个。
*
* 本算法利用62个可打印字符,通过随机生成32位UUID,由于UUID都为十六进制,所以将UUID分成8组,每4个为一组,然后通过模62操作,
* 结果作为索引取出字符, 这样重复率大大降低。
*
* 经测试,在生成一千万个数据也没有出现重复,完全满足大部分需求。
*
* @author wangfan
* @date 2017-3-28 下午1:11:31
*/
public
class
UUIDUtil
{
private
UUIDUtil
()
{
throw
new
IllegalStateException
(
"Utility class"
);
}
private
static
String
[]
chars
=
new
String
[]
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
,
"g"
,
"h"
,
"i"
,
"j"
,
"k"
,
"l"
,
"m"
,
"n"
,
"o"
,
"p"
,
"q"
,
"r"
,
"s"
,
"t"
,
"u"
,
"v"
,
"w"
,
"x"
,
"y"
,
"z"
,
"0"
,
"1"
,
"2"
,
"3"
,
"4"
,
"5"
,
"6"
,
"7"
,
"8"
,
"9"
,
"A"
,
"B"
,
"C"
,
"D"
,
"E"
,
"F"
,
"G"
,
"H"
,
"I"
,
"J"
,
"K"
,
"L"
,
"M"
,
"N"
,
"O"
,
"P"
,
"Q"
,
"R"
,
"S"
,
"T"
,
"U"
,
"V"
,
"W"
,
"X"
,
"Y"
,
"Z"
};
/**
* 生成8位uuid
* @return
* @author wangfan
*/
public
static
String
randomUUID8
()
{
StringBuilder
shortBuffer
=
new
StringBuilder
();
String
uuid
=
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
String
str
=
uuid
.
substring
(
i
*
4
,
i
*
4
+
4
);
int
x
=
Integer
.
parseInt
(
str
,
16
);
shortBuffer
.
append
(
chars
[
x
%
0x3E
]);
}
return
shortBuffer
.
toString
();
}
/**
* 生成32位uuid
* @return
* @author wangfan
*/
public
static
String
randomUUID32
(){
return
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录