一个 64 位分布式 ID 生成器 - Siddharth Sabron

主要观点:

  • 独特的 ID 生成对应用很关键,用于表示表中的唯一行,常作为主键用于搜索。
  • 不建议用Math.random() + epoch或随机字符串作为主键,因其在性能等方面存在诸多问题,如比较慢、索引大、易碎片化、参考局部性差等。
  • 数值型、顺序 ID 更好,如采用类似雪花算法的方式,具有比较快、索引小、减少碎片化、提高局部性等优势。
  • 介绍了数据库内部使用的 B-Trees 结构及相关操作,以及generateInternalId(int shardId)方法生成 64 位唯一 ID 的原理,包括时间戳、分片 ID、序列数的组合及位运算过程等,并给出了 Java 实现代码及重要考虑事项(未处理序列溢出、时钟漂移等情况)。

关键信息:

  • ID 结构为 64 位,包含 41 位时间戳、10 位分片 ID、12 位序列数及额外 1 位。
  • 时间戳基于2023-01-01 00:00:00 UTCSystem.currentTimeMillis()计算,约 69.7 年循环。
  • 10 位分片 ID 可区分 1024 个数据库分片或应用实例。
  • 12 位序列数在同一毫秒同一分片内递增,最多 4096 个。
  • 代码通过位运算组合各部分生成 ID,generateInternalId方法使用synchronized保证线程安全。
  • 重要考虑事项包括处理序列溢出、时钟漂移及分片 ID 分配等。

重要细节:

  • 数据库索引使用 B-Trees 或变体,搜索、插入等操作时间复杂度为 O(log n),字符串比较比整数慢,随机字符串导致索引碎片化和较差的参考局部性。
  • 顺序 ID 插入在 B-tree 索引的最右叶节点,减少碎片化和提高写入性能。
  • generateInternalId方法中的epoch为自定义起始时间戳,sequence使用AtomicInteger保证原子性递增并通过& 0xFFF限制在 12 位范围内。
  • 示例展示了根据当前时间、分片 ID 和序列数生成具体 ID 的过程。
  • 提到在个人项目Url Shortener中使用了该方法。
阅读 7
0 条评论