分布式id生成方案

1. segment 号段模式

1.1 普通号段

1.2 双buffer优化优化

2. 雪花算法 或者改进

雪花算法 一位固定位+41时间戳+10机器码+12序列号

雪花算法缺点:

时钟回拨

  • 记录最近一次生成时间进行比较,如果小于5ms等待两倍时间重试
  • 跨度过大直接抛异常人工处理

3. 案例

美团Leaf:https://tech.meituan.com/2019...

  • leaf-segment 方案

    • 优化:双buffer + 预分配
    • 容灾:Mysql DB 一主两从,异地机房,半同步方式
    • 缺点:如果用segment号段式方案:id是递增,可计算的,不适用于订单ID生成场景,比如竞对在两天中午12点分别下单,通过订单id号相减就能大致计算出公司一天的订单量,这个是不能忍受的。
  • leaf-snowflake方案

    • 使用Zookeeper持久顺序节点的特性自动对snowflake节点配置workerID
      • 1.启动Leaf-snowflake服务,连接Zookeeper,在leaf_forever父节点下检查自己是否已经注册过(是否有该顺序子节点)。
      • 2.如果有注册过直接取回自己的workerID(zk顺序节点生成的int类型ID号),启动服务。
      • 3.如果没有注册过,就在该父节点下面创建一个持久顺序节点,创建成功后取回顺序号当做自己的workerID号,启动服务。
    • 缓存workerID,减少第三方组件的依赖
    • 由于强依赖时钟,对时间的要求比较敏感,在机器工作时NTP同步也会造成秒级别的回退,建议可以直接关闭NTP同步。要么在时钟回拨的时候直接不提供服务直接返回ERROR_CODE,等时钟追上即可。或者做一层重试,然后上报报警系统,更或者是发现有时钟回拨之后自动摘除本身节点并报警
  • 百度UIDGenerator:

    • UidGenerator是Java实现的, 基于Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中, 支持自定义workerId位数和初始化策略, 从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。 在实现上, UidGenerator通过借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万。