微服务 id 生成策略
数据库自增 ID
最简单的实现方式是使用数据库的 id 自增策略,如 MySQL 的 auto_increment。如果两台数据库分别设置不同步长,可以生成不重复 ID,从而实现高可用。
- 优点
- 实现简单,容易理解,单调自增,绝对有序。
- 缺点
- 强依赖 DB,当 DB 异常时整个系统不可用,属于致命问题。ID 发号性能瓶颈限制在单台 MySQL 的读写性能。
UUID 系列
参考:https://zhuanlan.zhihu.com/p/70375430
结合机器的网卡、当地时间、一个随记数来生成 UUID。存在一些 UUID 的变种也是不错的实现。
优点
- 本地生成,生成简单,性能非常好,高可用。
缺点
- 长度过长,不易存储,无序不可读,查询效率低。
- 信息不安全,基于 MAC 地址生成 UUID 的算法可能会造成 MAC 地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。
- UUID 的无序性可能会引起数据位置频繁变动,严重影响性能。
Redis 实现 ID
Redis 的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保证生成的 ID 肯定是唯一有序的。 举例,使用 Redis 来生成每天从 0 开始的流水号。比如订单号 = 日期 + 当日自增长号。可以每天在 Redis 中生成一个 Key ,使用 INCR 进行累加。
参考:https://www.cnblogs.com/agilestyle/p/13194027.html
- 优点
- 灵活方便,且性能优于数据库。
- 数字 ID 天然排序,通过合理设计可以得到更具有表达能力的 ID。
- 缺点
- 引入 Redis,编码和配置的工作量比较大。
- 如果 ID 是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定 URL 即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要 ID 无规则、不规则。
Twitter 的 snowflake 算法生成 ID
GitHub:https://github.com/twitter-archive/snowflake/releases/tag/snowflake-2010
参考:https://www.cnblogs.com/xiaofeiyang/p/13111548.html
优点
- 时间有序,毫秒数在高位,自增序列在低位,整个 ID 都是趋势递增的。
- 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成 ID 的性能也是非常高的。
- 可以根据自身业务特性分配 bit 位,非常灵活。
- Long 型。
缺点
- 依赖于机器的时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。
百度 UidGenerator
参考:https://www.cnblogs.com/yeyang/p/10226284.html
GitHub:https://github.com/baidu/uid-generator
- 优点
- 同上 Twitter 的 snowflake 算法生成 ID
- 缺点
- 需要 MySQL(内置 WorkerID 分配器, 启动阶段通过 DB 进行分配; 如自定义实现, 则 DB 非必选依赖)
美团 Leaf
参考:https://tech.meituan.com/2019/03/07/open-source-project-leaf.html
GitHub:https://github.com/Meituan-Dianping/Leaf
优点
- 高可用容灾。
- ID 号码是趋势递增的 8byte 的 64 位数字,满足数据库存储的主键要求。
缺点
- DB 宕机会造成整个系统不可用。
- 比较复杂。
MongoDB 的 ObjectId
参考:https://docs.mongodb.com/manual/reference/method/ObjectId/
通过“时间+机器码+pid+inc”共 12 个字节,通过 4+3+2+3 的方式最终标识成一个 24 长度的十六进制字符。
- 优点
- 轻量型的,不同的机器都能用全局唯一的同种方法方便地生成它。
- 本地生成,含时间戳,有序,成本低。
- 安全性高。
- 比较短,24 位
- 缺点
- 比较长,难于记忆。
- 使用机器 ID 和进程 ID,64 位 Long 无法存储,只能生成特殊 ObjectId 对象。
