前言
在分布式系统中,很多场景都需要一个唯一值来标记某个数据或者资源,那这个唯一值就是分布式ID,目前分布式ID的生成方式有如下几种:
- 数据库主键
- UUID
- 基于Redis
- 基于Zookeeper:使用zNode(此文不讲解)
- 雪花算法
数据库主键
该方案是基于数据库主键自增来实现的,新增一条数据,主键自动增长
优点:
- 天然自增
- 实现简单
缺点:
- 有数据库依赖
- 性能差
- 单点故障:可以通过做数据库的高可用规避
- 不方便分库分表:可以通过设置步长规避,比如分了n个库m个表,那就每次增加n+m
UUID
通过java自带的UUID生成的类库实现
优点:
- 实现简单
- 性能高
- 没有数据库依赖
缺点:
- 不能保证自增
- 对排序有影响
- 索引代价大:字符作为索引效率较差
- 不可读
解决自增的方案:NHibernate在其主键生成方式中提供了Comb算法(combined guid/timestamp)。保留GUID的10个字节,用另6个字节表示GUID生成的时间(DateTime)
解决不可读的方案:可以使用UUID to Int64的方法
Redis
通过redis提供的incy或者incyBy原子操作实现分布式ID
优点:
- 天然自增
- 性能高
- 没有数据库依赖
缺点:
- 需要编程,实现复杂
雪花算法
雪花算法生成的分布式ID是64位的,其中首位不用,一般都是0,接下来的41位是时间戳,再接下来10位是机器号,其中前5位是机房好,后五位是机器号,最后13位为自增序列,从0开始,最高到4095,即表示4096个自增序列
雪花算法的具体实现本文不赘述,网上有很多实现,自行参考即可
优点:
- 实现简单
- 可以保证自增
- 性能高
- 没有数据库依赖
缺点:
- 时间拨片问题
- 机器ID上限
时间拨片解决:由于不同机器的时间是可以不同的,因此会造成id重复的问题,往往是采用历史时间的方式来防止该问题
机器ID上限:增加位数,并放到低位,防止被恶意爬取