分布式ID生成器的解决方案

为什么需要分布式ID生成器 ?

简单介绍下分布式ID生成器出现的背景:
1.目前微服务架构盛行,在分布式系统中的操作中都会有一些全局性ID的需求,比如消息中和http请求中或者消息中的唯一标识号,作为交易双方的幂等条件。
2.交易系统中有各种业务编号的需求,这种编号可能需要暴露给用户(比如订单号),但又不能被猜到业务编号的生成规则。
3.业务编码可能需要体验一些业务信息。

应该具备怎么样的特性?

高可用
可伸缩
唯一性(分布式环境)
趋于递增
效率高

常规方案

目前主要有以下几种常见的技术方案
1. UUID
简介:
UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分
UUID是由一组32位数的16进制数字所构成,是故UUID理论上的总数为1632=2128,约等于3.4 x 1038。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
UUID的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的32个字符。示例:
550e8400-e29b-41d4-a716-446655440000
也就是说每秒产生10亿笔UUID,100年后只产生一次重复的机率是50%
优点:
- 本地生产,没有任何的网络消耗
- 可以任意水平扩展
- 生成效率高
- 生成节点不限
缺点 :
- 占用的空间大,有128bit
- 无法做到趋势递增
- 索引效率很差
- 作为业务主键的话,可读性差

2. 数据库自增序列ID
简介:
数据库自增列,比如oacle的序列创建语法:
CREATE SEQUENCE seq_name– seq_name为序列名称,自定义;
INCREMENT BY 1 – 每次加幅度:1,2,3;
START WITH 1 – 起始序号,以实际情况而定;
NOMAXvalue – 不设置最大值,或设定最大值: maxvalue 99999999;
NOCYCLE – 一直累加,不循环; 或循环使用 cycle ;
CACHE 10; –设置缓存序列个数,如果系统down掉了或者其它情况将会导致序列不连续,也可以设置为———NOCACHE

一种常见的做法:
可以在加入时间戳比如: 201707111317+机器集群号(可以在本地或者配置中心维护,比如携程的阿波罗)+N位序列位数(左边不够补零)。
优点:
- 可以实现完全递增
- 部署比较简单,只需要有DB服务器
- 可读性好,可以根据自己的业务规则进行定义。
缺点 :
- 生成效率低,完全取决于数据库的性能指标;
- 依赖于数据库,如果DB发生问题,可能会导致一系列的问题,即使通常情况下我们是可以主从切换的。

3. 雪花算法
简介:
这里写图片描述
各个字段解析:
这里写图片描述

整个ID的构成大概分为这么几个部分,时间戳差值,机器编码,集群编码,序列号。从左向右依次:时间戳差值,占了42位;机器编码5位;集群编码5位;序列号12位。所有的拼接用位运算拼接起来。

long nextId = ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence

说明如下:
timestamp - twepoch:当前时间的时间戳减去一个程序开始运行的时间戳
(timestamp - twepoch) << timestampLeftShift:timestampLeftShift的值为22,将差值左移22个位数,左边补零。
(datacenterId << datacenterIdShift):datacenterIdShift值为17,集群位位数,左移17位
(workerId << workerIdShift):workerIdShift值为12,机器编码为5位,左移12位
sequence:最大位数为12

优点:

  • 生成序列效率高,单机每秒可生成几百万的序列。
  • 趋势递增
  • 可读性好
  • 高可用,可伸缩

缺点 :
- 依赖于时间戳,如果服务器时间被回拨,可能会存在重复的可能性。
解决方案:获取当前的时间戳,校验当前时间是否大于等于上次生成ID的时间, 如果成功则生成ID,设置上次生成ID时间=当前时间;否则生成ID失败。
- 如果服务器挂了,时间被回拨,怎么搞?
解决方案:可以将最后记录的服务器时间写入文件,读取文件中的持久化的写入时间,校验写入时间与当前时间

核心代码参见:
https://github.com/jasonhsu2017/happy-springboot.git
工具类:SnowflakeIdGenUtil

猜你喜欢

转载自blog.csdn.net/xuxian6823091/article/details/81003744