思维导图
思维导图.png技术选型
数据库自增长序列
- 最常见的方式, 可通过主键或者其他字段生成
优点
- 简单,代码方便,性能可以接受
- 数字ID天然排序,对分页或者需要排序的结果很有帮助
缺点
- 不同数据库语法和实现不同,数据库迁移的时候或多数据库版本支持的时候需要处理
- 在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险
- 在性能达不到要求的情况下,比较难于扩展
- 如果遇见多个系统需要合并或者涉及到数据迁移会相当痛苦
UUID
优点
- 简单,代码方便
- 生成ID性能非常好,基本不会有性能问
缺点 :
- 没有排序,无法保证趋势递增
Redis生成ID
- 主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现
优点
- 不依赖于数据库,灵活方便,且性能优于数据库。
- 数字ID天然排序,对分页或者需要排序的结果很有帮助。
缺点
- 如果系统中没有Redis,还需要引入新的组件,增加系统复杂度。
- 需要编码和配置的工作量比较大。
利用zookeeper生成唯一ID
优点
- 主要通过其znode数据版本来生成序列号,可以生成32位和64位的数据版本号,客户端可以使用这个版本号来作为唯一的序列号
缺点
- zk一般多步调用API,如果在竞争较大的情况下,需要考虑使用分布式锁。高并发情况下,竞争大,CP模式也不太适合高并发场景
滴滴开源
- 基于Segment(号段)模式: 如果采用数据库获取ID的形式,那每次都要进行一次数据库查询, 每次查询会对数据库造成很大压力,可以采用双Buffer优化
- star 1.8K
百度开源
-
基于Snowflake雪花算法模式: 基于64位数实现,下图为Snowflake算法的ID构成图
雪花算法.png - star 4.5K
美团开源
- 支持Segment/Snowfake两种模式切换,相比滴滴/百度开源更灵活
- star 5.2K
原理详解
Segment(号段模式)
- 数据库模式获取分布式ID对数据库压力比较大,这里考虑用双层Buffer模式缓解数据库压力
对比项 | 含义 | 值 |
---|---|---|
tag | 业务标识 | 值 |
max_id | id最大值 | 10000 |
step | 步长 | 1000 |
第一层Buffer
- 分布式ID生成服务每次去数据库获取一个号段的值,用完之后需要重新从数据库获取新的号段。第一层Buffer的处理方式是: 假设步长为1000,那就是等有1000个号码消耗完以后才会取下一个号段,这期间应用侧自己计算值,这样数据库压力降低为1/1000
第二层Buffer
-
极端情况下,可能还是有大量步长用完需要获取步长和最大id的操作,对数据库造成一定影响。因此增加双Buffer策略服务内部有两个segment(号段)缓存区。当buffer1使用比如10%时,另起线程获取备用buffer2
第二层Buffer.png
使用场景
- 可接受非严格递增: 应用不同服务获取步长肯能不太一样
- 可接受能被猜测量级: 号段模式生成的ID容易猜测量级,例如对于订单号场景,从今天中午下单的订单号减昨天中午下单的订单号可大致预估订单量级
Snowflake(雪花算法)
雪花算法.png优缺点
- 算法自身无外部依赖,生成性能高,且生成ID安全性较强,保持全局有序递增状态
- 长度太长比如商品Id这种一般是短Id的不太适合
- 机器时间回拨可能会导致时间戳
改进
- 工作机器id为整形,如果服务器数据量大,那要自定义生成机器id: 引入zk,如果机器ip和服务标识不变的话可以固定一个工作机器id
- 时间回拨: 采用业界对于时间回拨的处理方式(首次等待,即等待一段回拨时间)
网友评论