分布式 id 生成方案
分布式 ID 需满足唯一性、有序递增性、高可用性、带时间性。
- UUID:通过本地算法生成,结合网卡、时间和随机数
- 本地生成,生成简单,性能好,没有高可用风险
- 但长度长、不可读、查询效率低。
- 数据库自增 ID:使用数据库的 id 自增策略,如 MSQL 的 auto increment。并且可以使用两台数据库分别设置不同步长,生成不重复 ID 的策略来实现高可用。使用数据库自增 ID,绝对有序,高可用
- 数据库生成的 ID 绝对有序,高可用实现方式简单
- 需要独立部署数据库实例,成本高,有性能瓶颈,效率较低
- 批量生成 ID:一·次按需批量生成多个 ID,每次生成都需要访问数据库,将数据库修改为最大的 ID 值,并在内存中记录当前值及最大值。
- 避免了每次生成 ID 都要访问数据库并带来压力,提高性能
- 属于本地生成策略,存在单点故障,服务重启造成 ID 不连续
- Redis 生成 ID:Redis 的所有命令操作都是单线程的,本身提供像 incr 和 increby 这样的自增原子命令,所以能保证生成的 ID 肯定是唯一有序的。
- 不依赖于数据库,灵活方便,且性能优于数据库; 数字 ID 天然排序,对分页或者需要排序的结果很有帮助。
- 如果系统中没有 Redis,还需要引入新的组件,增加系统复杂度; 需要编码和配置的工作
- 量比较大。
- 雪花算法: 推特公司发明,基于时间戳、机器位和序列号生成,高性能、低延迟、有序,一般不会重复。
- 高性能,低延迟,按时间有序,一般不会造成 ID 碰撞 (每毫秒有 4096 个 id)
- 需要独立的开发和部署,依赖于机器的时钟
- bigint,19 位纯数字,对于前端会出现精度缺失的情况
- 百度 UidGenerator
- 标准雪花算法最怕时钟回拨(时间倒流),会导致 ID 重复。
- 时间戳秒级 :标准雪花是毫秒级,百度改为秒级,节省了位数。
- 美团 Leaf
- Leaf-segment(号段模式):不依赖时间戳。从数据库批量取出一批 ID(如 1000 个)缓存在本地
- Leaf-snowflake:标准雪花算法的改进版。使用 Zookeeper 来管理 WorkerID
- ULID (Universally Unique Lexicographically Sortable ID)
- 格式 :48 位时间戳 + 80 位随机数。
- 编码 :使用 Crockford’s Base32 编码(只包含 0-9 和 A-Z,排除了 I, L, O, U 避免混淆)。
- 字符串有序 :按字符串字典序排序等于按时间排序(这点雪花算法的 Base64 编码做不到)。
- 长度 26 字符 (16 字节)
- 不需要机器节点 id
- TSID (Time-Sorted Identifier)
- 结合了 Twitter 雪花算法和 ULID 的特点。
- 格式 :通常也是字符串形式,兼顾时间排序和唯一性。
- 特点在于它试图在保持排序的同时,提供比 ULID 更好的物理存储特性(有些实现会尽量让 ID 长度更短)。
- 长度 13 字符 (8 字节)
- 需要机器节点 id
- MongoDB ObjectId
- MongoDB 默认的主键 ID,也是一种类雪花算法。
- 格式 :12 字节的十六进制字符串(24 个字符)。
- 组成 :4 字节时间戳 + 3 字节机器 ID + 2 字节进程 ID + 3 字节计数器。
- 特点 :天生分布式,无需配置,按时间大致有序。
<br/>
事务的报错和版本回滚
- 在正常的订单流程重,库存扣减成功,用户服务成功,但是在生成订单的过程失败了
- 在积分消费中,用户 1000 积分消费 700 积分,过程中又消费了 300 积分购买商品,但是在消费 700 积分的扣减过程订单失败,事务要进行回滚返回到 1000 积分,多给了用户 300 积分
- 例如在上面的积分中,店铺手动给用户添加 2000 积分,积分回滚的时候要保证 2000 积分的添加
正文完
发表至: PM
2025-08-08