打算用雪花算法生成 ID
这里面有个机器 ID
如果我们部署多个服务的话
在没有注册中心的场景下,怎么能够方便的生成 ID 啊
请大家赐教。
1
TsubasaHanekaw 2022-09-26 12:05:07 +08:00
网卡 mac 啊,硬盘序列号啊 这种
|
2
qq976739120 2022-09-26 12:08:25 +08:00
用各个硬件的唯一标识号
|
3
hzj629206717 2022-09-26 12:11:57 +08:00
也不是很复杂,需要额外引入 Redis 或 MySQL ,每个实例去抢占一个 machine id 并 keep alive 。剩下的就是实现的可靠性了。
|
4
changdy 2022-09-26 12:19:49 +08:00
楼上几个 回答是有偏颇的, 如果要做到 服务无感,随时扩容,缩容 ,是需要 一个类似注册中心的 .
我们之前的做法是 固定部署几个实例 ,每个实例的序号就是 机器 id. 当然这也会有问题, 比如项目部署接单会出现 旧的实例没完全下线,新的已经上线了.还有就是无法随时扩容 . 这个其实也是服务治理中的一环了. |
5
wu00 2022-09-26 12:51:41 +08:00 2
10bit 机器码,便捷就集群内网 IP % 1024 ,量不大没啥问题。
严谨点就按#3 #4 说的注册中心 |
6
git00ll 2022-09-26 13:18:08 +08:00
redis 存一个自增的序号
|
7
lmshl 2022-09-26 13:44:00 +08:00
UUID v1 满足不了么?
“版本 1 - UUID 是根据时间和 节点 ID (通常是 MAC 地址)生成;” -- 维基百科 |
11
LeegoYih 2022-09-26 14:14:36 +08:00
|
12
Bromine0x23 2022-09-26 14:40:36 +08:00
说到 UUID 的话,有 V6 V7 两个草案阶段的变种是自增的
|
13
Jooooooooo 2022-09-26 14:46:26 +08:00
不要太复杂, 直接用个 mysql 主键维护一下.
每个机器启动的时候都去库里拿一下自己的 id, 如果没有就 insert. 但这里得注意, 如果机器码是三位的, 那集群下机器数量不能超过 1000, 还有废弃机器占用 id 的问题. |
14
wangritian 2022-09-26 15:28:04 +08:00
k8s 有状态应用的 hostname 或 redis 的 incr (程序版本为 key )
|
16
ScepterZ 2022-09-26 19:24:45 +08:00
容器编号如何
|
17
odirus 2022-09-26 19:33:19 +08:00
我们刚好有这个功能:
1. 提供一个服务端来下发未使用的 workerId ; 2. 客户端获取到 workerId 后定期上报心跳到服务端; 3. 服务端维护 workerId 的心跳信息(并针对异常心跳做断言,提前发现问题),一段时间内没心跳后标记为未使用; 当然还有一些细节: 1. 要考虑某个 Pod 反复重启的情况; 2. 引入命名空间的概念,针对数据不会交叉的场景隔离命名空间,不然 workerId 根本不够用; 3. 我们在 MySQL 还实现了一条有意思的 SQL:通过无锁的方式获取未被使用的 workerId ,返回范围在[0-MAX],不用做取模等; |
18
xuanbg 2022-09-26 20:23:08 +08:00
首选注册中心分配,部署多个服务没有注册中心有些不可思议啊。
|
19
zibber 2022-09-26 21:14:53 +08:00
在 etcd 维护一个 key, pod 启动的时候写入 etcd, pod 停止的时候从 etcd 删掉
|
20
cp19890714 2022-09-27 09:53:35 +08:00
使用 Redis ,几行代码即可。
``` public class DistributedWorkerIdGenerator { private static final String ID_WORKER_ID_INCREMENT_KEY = "ID_WORKER_ID_INCREMENT"; private static final int MAX_WORKER_ID = 64; private static final int EXPIRE_SECONDS = 3600; private static final String ID_WORKER_ID_PREFIX = "ID_WORKER_ID_"; /** * 获取新的 workId * 1.维护自增数字, 数字每次增加 1 * 2.如果 workerId 已经存在, 则循环获取新的 workerId * * @param redisTemplate * @return workId */ Long acquireId(RedisTemplate<String, Object> redisTemplate) { RedisAtomicLong redisAtomicLong = new RedisAtomicLong(ID_WORKER_ID_INCREMENT_KEY, redisTemplate.getConnectionFactory()); Long incrementIndex; Long workerId; for (int i = 0; i < MAX_WORKER_ID; i++) { incrementIndex = redisAtomicLong.getAndIncrement(); workerId = incrementIndex % MAX_WORKER_ID; if (redisTemplate.opsForValue().setIfAbsent(ID_WORKER_ID_PREFIX + workerId, workerId, EXPIRE_SECONDS, TimeUnit.SECONDS)) { return workerId; } } throw new ApplicationException("Generate workId failed"); } /** * 续签 workerId * 服务实例需要通过定时任务续签, 定时任务的时间间隔需要小于过期时间 * * @param redisTemplate * @param workerId */ void renewalId(RedisTemplate<String, Object> redisTemplate, Long workerId) { redisTemplate.expire(ID_WORKER_ID_PREFIX + workerId, EXPIRE_SECONDS, TimeUnit.SECONDS); } ``` |
21
Marcoo 2022-09-27 16:18:51 +08:00
我们是使用 Redis ,起一个自增一个 然后检查对应 key (有 5 分钟失效时间)是否存在 如果存在则再自增。
然后维持好心跳,一分钟发次心跳,续 5 分钟的失效时间 |