美团 Leaf-snowflake 分布式 ID 生成器 k8s 改造的想法

美团 Leaf-snowflake 分布式 ID 生成器 k8s 改造的想法

复制代码
+--------------------------------------------------------------------------+
| 1 Bit Unused | 41 Bit Timestamp |  10 Bit workerID  |   12 Bit Sequence ID |
+--------------------------------------------------------------------------+

snowflake 生成的 ID 共 64 位:

  1. 1 bit 符号位,固定 0,保证 ID 永远为正数
  2. 41 bit 毫秒时间戳,相对于起始基准时间的毫秒偏移量
  3. 10 bit 机器号,用于标识数据中心和机器节点
  4. 12 Bit,同一毫秒内自增序号

原始的 snowflake 有两个问题:

  1. workerId 需要手动配置,服务规模较大的话手动配置成本太高
  2. 时钟回拨导致生成的 ID 重复

美团 Leaf-snowflake 解决了这两个问题。

自动生成 workerID

服务启动时遍历 zookeeper PATH_FOREVER 节点的所有子节点,子节点的 key 格式为 {ip}:{port}-xxxxxxxxxx,然后截取 - 的前面和本机的 {ip}:{port} 对比,如果一样则说明之前注册过,截取 - 后面的字符串转为 int 作为 workerId。若不存在,则会在 zookeeper 创建一个格式为 {PATH_FOREVER}/{ip}:{port}-持久顺序 znode (比如 /snowflake/com.sankuai.leaf.opensource.test/forever/192.168.124.1:8080-0000000000),截取出 workerId 存入本地文件 workerID.properties 中。如果服务启动时无法连接 zookeeper,本地文件 workerID.properties 中的 workerId 可以作为一个 failover。

本地启动后 zookeeper 内容如下,forever 只有一个节点 192.168.124.1:8080-0000000000,节点的值中包含了服务器的 ip、port、当前时间戳:

shell 复制代码
[zk: 127.0.0.1:2181(CONNECTED) 40] ls /snowflake/com.sankuai.leaf.opensource.test/forever
[192.168.124.1:8080-0000000000]

[zk: 127.0.0.1:2181(CONNECTED) 18] get /snowflake/com.sankuai.leaf.opensource.test/forever/192.168.124.1:8080-0000000000 
{"ip":"192.168.124.1","port":"8080","timestamp":1783139487629}

时钟回拨

  1. 在自动生成 workerID 的同时在 value 中上报了机器的当前时间,除此之外还会开启一个定时任务每 3s 上报一次机器的当前时间。

  2. 在启动时会去查询最后一次上报的时间,如果当前时间小于最后一次上报的时间则直接抛出异常,停止服务,防止生成的 ID 重复。

  3. 如果是新服务节点,需要综合对比其余 Leaf 节点的系统时间来判断自身系统时间是否准确,具体做法是取 leaf_temporary 下的所有临时节点(所有运行中的Leaf-snowflake节点)的服务IP:Port,然后通过RPC请求得到所有节点的系统时间,计算 sum(time)/nodeSize

    1. abs( 系统时间-sum(time)/nodeSize ) < 阈值,认为当前系统时间准确,正常启动服务,同时写临时节点 leaf_temporary/${self} 维持租约。
    2. 否则认为本机系统时间发生大步长偏移,启动失败并报警。
  4. 如果时钟回拨时间较短,可以 wait 一会,等本机时间追上上次上报时间后再提供服务。

GitHub - Meituan-Dianping/Leaf: Distributed ID Generate Service 中我只找到了 1、2,第 3、4 条是在 Leaf------美团点评分布式ID生成系统 | 美团 · 技术团队 提到的。

k8s 改造的想法

k8s StatefulSet 可以为 pod 提供稳定的 hostname、稳定唯一的网络标识符、稳定的存储,完全可以替代 zookeeper 的作用。

假设 StatefulSet 名称为 leaf,则各个 pod 的 hostname 为 leaf-0、leaf-1、leaf-2,Headless Service 名称为 leaf.svc 提供稳定的网络标识符,且使用 PVC 挂载了存储,leaf-0 会使用 pvc-0,leaf-1 会使用 pvc-1,pod 和 pvc 之间的关联是稳定的,重启后也是如此。使用 8080 端口启动所有 leaf 服务。

  1. 自动 workerID:直接解析 hostname 使用 - 后面的序号作为 workerID 即可,甚至不需要本地 workerID.properties 文件作为 failover。
  2. 上报本机时间:不再上报给 zookeeper,而是存储在 pvc 挂载目录的本地文件中。
  3. 获取其他 leaf 节点的服务IP、Port:不再使用 leaf_temporary 临时节点,改为直接调用 k8s API 查询 StatefulSet 下的 pod name。
  4. 访问其他 leaf 节点获取系统时间:通过 <pod-name>.<headless-svc-name> 访问,例如访问 leaf-3 使用 leaf-3.leaf.svc:8080

参考

相关推荐
ShirleyWang0121 天前
让headlamp控制台能访问
linux·服务器·python·k8s·k3s
spider_xcxc1 天前
K8s 部署学习笔记
docker·容器·kubernetes·云计算·k8s
ShirleyWang0121 天前
Day02 K3s NGF(Nginx Gateway Fabric)单 Worker 环境网关更新与故障处置 SOP
linux·服务器·python·k8s·k3s
ShirleyWang0121 天前
DAY01 K3s 私有化部署排障复盘与 SOP
linux·服务器·k8s·k3s·企业部署
james的分享4 天前
AI数据平台之Snowflake
snowflake·ai数据中台
XUHUOJUN5 天前
AKS 不是安装在 Windows Server 上,而是运行在 Windows Server 之上的 Azure 平台能力
windows·架构·k8s·azure local·azure stack
Geek-Chow5 天前
Connecting kubectl to a Private EKS Cluster Over an Internal Domain
kubernetes·k8s·aws
spider_xcxc7 天前
Docker Compose 容器通信详解:同一个 Compose 文件才能互通吗?
docker·容器·k8s·容器化·容器网络
欢醉12 天前
k8s调用服务异常cannot allocate memory
kubernetes·k8s
万里侯15 天前
GitOps 漂移检测:集群里改了配置,Git 还以为一切正常
微服务·容器·k8s