分布式主键的两大需求:
- 全局唯一
- 趋势有序
数据库自增
优点:
- 简单
- 能够保证唯一性
- 能够保证递增性
- 主键的步长是固定且可自定义的
缺点:
- 可用性难以保证:数据库常见架构是 一主多从 + 读写分离,生成自增主键是写请求,有单点故障的风险
- 扩展性差,性能有上限:因为写入是单点,数据库主库的写性能决定主键的生成性能上限,并且难以扩展
单点批量主键生成服务
优点:
- 保证了主键生成的绝对递增有序
- 大大降低了数据库的压力,主键生成可以做到每秒生成几万几十万个
缺点:
- 服务仍然是单点
- 如果服务挂了,服务重启之后,继续生成的主键可能会不连续,中间出现空洞(服务内存保存着0,1,2,3,4,数据库中最大主键是4,分配到3时,服务重启了,下次会从5开始分配,3和4就成了空洞,不过这个问题不大)
- 虽然每秒可以生成几万几十万个主键,但还是有性能上限,无法进行水平扩展
UUID / GUID
优点:
- 本地生成,不需要进行远程调用,时延低
- 扩展性好,基本可以认为没有性能上限
缺点:
- 无法保证趋势递增
- UUID 过长,往往用字符串表示,作为主键建立索引查询效率低;常见优化方案为“转化为两个uint64整数存储”或者“折半存储”,但折半后不能保证唯一性
取当前毫秒数
优点:
- 本地生成,不需要进行远程调用,时延低
- 生成的主键趋势递增
- 生成的主键是整数,建立索引后查询效率高
缺点:
- 如果并发量超过1000,会生成重复的主键;改用微秒可以降低冲突概率,但每秒最多只能生成100万个主键,再多的话就一定会冲突了,所以使用微秒并不从根本上解决问题。
使用 Redis 自增
优点:
- 不依赖数据库,灵活方便,且性能优于数据库
- 天然排序,对分页或者需要排序的结果很有帮助
缺点:
- 如果系统中没有Redis,还需要引入新的组件,增加系统复杂度
- 需要编码和配置的工作量比较大
Twitter 开源的 Snowflake 算法
详情见这里