美团 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 bit 符号位固定 0保证 ID 永远为正数41 bit 毫秒时间戳相对于起始基准时间的毫秒偏移量10 bit 机器号用于标识数据中心和机器节点12 Bit同一毫秒内自增序号原始的 snowflake 有两个问题workerId 需要手动配置服务规模较大的话手动配置成本太高时钟回拨导致生成的 ID 重复美团 Leaf-snowflake 解决了这两个问题。自动生成 workerID服务启动时遍历 zookeeperPATH_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、当前时间戳[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}时钟回拨在自动生成workerID的同时在 value 中上报了机器的当前时间除此之外还会开启一个定时任务每 3s 上报一次机器的当前时间。在启动时会去查询最后一次上报的时间如果当前时间小于最后一次上报的时间则直接抛出异常停止服务防止生成的 ID 重复。如果是新服务节点需要综合对比其余 Leaf 节点的系统时间来判断自身系统时间是否准确具体做法是取leaf_temporary下的所有临时节点(所有运行中的Leaf-snowflake节点)的服务IPPort然后通过RPC请求得到所有节点的系统时间计算sum(time)/nodeSize。若abs( 系统时间-sum(time)/nodeSize ) 阈值认为当前系统时间准确正常启动服务同时写临时节点leaf_temporary/${self}维持租约。否则认为本机系统时间发生大步长偏移启动失败并报警。如果时钟回拨时间较短可以 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-2Headless Service 名称为 leaf.svc 提供稳定的网络标识符且使用 PVC 挂载了存储leaf-0 会使用 pvc-0leaf-1 会使用 pvc-1pod 和 pvc 之间的关联是稳定的重启后也是如此。使用 8080 端口启动所有 leaf 服务。自动workerID直接解析 hostname 使用-后面的序号作为workerID即可甚至不需要本地workerID.properties文件作为 failover。上报本机时间不再上报给 zookeeper而是存储在 pvc 挂载目录的本地文件中。获取其他 leaf 节点的服务IP、Port不再使用leaf_temporary临时节点改为直接调用 k8s API 查询 StatefulSet 下的 pod name。访问其他 leaf 节点获取系统时间通过pod-name.headless-svc-name访问例如访问 leaf-3 使用leaf-3.leaf.svc:8080。参考Leaf——美团点评分布式ID生成系统 | 美团 · 技术团队GitHub - Meituan-Dianping/Leaf: Distributed ID Generate Service · GitHub