在分布式系统中,如何生成分布式ID?

下面有几种常用方案,可以根据具体业务场景来选择。

1. UUID

UUID 指在一台机器上生成的数字,它保证在同一时空中的所有机器都是唯一的。

UUID 由以下几部分组成:

  • 当前日期和时间。
  • 时钟序列。
  • 全局唯一的IEEE机器识别码(如网卡MAC地址等)。
在分布式系统中,如何生成分布式ID?

在Java中,使用UUID 非常方便。

UUID uuid = UUID.randomUUID();

UUID 具有如下优点:

  • 使用方便,很容易实现。
  • 性能很高。

缺点:

  • 没有顺序,不能保证单调递增。
  • 太长,总长32位,无论是存储还是传输,缺点都比较明显。

2. SnowFlake 雪花算法

Twitter 的SnowFlake 是一个非常优秀的ID生成方案,实现也比较简单,8Byte 是一个Long,等于64bit,核心代码就是毫秒级时间41位+10位机器ID+毫秒序列12位。

https://github.com/twitter-archive/snowflake

在分布式系统中,如何生成分布式ID?

SnowFlake 的优点如下:

  • 比UUID 短,一般为9-17位。
  • 生成的ID是数字,可以做到单调递增。由于无法统一分布式环境中每台服务器的时钟,它只能做到单台机器单调递增,无法做到全局递增。
  • 性能非常出色,吞吐量达到几十万TPS。

SnowFlake的结构如下(每部分用-分开):

在分布式系统中,如何生成分布式ID?

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年),然后是5位DataCenterID和5位WorkerID(10位的长度最多支持部署1024个节点) ,最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)。

一共加起来刚好64位,为一个Long型。(转换成字符串后长度最多19)

SnowFlake 生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由DataCenterID和WorkerID作区分),并且效率较高。经测试SnowFlake 每秒能够产生26万个ID。

如下SnowFlake 算法生成的2进制和Long 型的唯一ID。

在分布式系统中,如何生成分布式ID?

关于《SnowFlake-Java版雪花算法》实现方案和演示,可以查看小编的另外一篇文章。

3. Ticket Server

Ticket Server 是 Flickr 采用的一种分布式ID 生成方案,利用 MySQL 自增长ID 实现。

它的设计思路是利用数据库中 auto increment 的特性和MySQL 特有的 REPLACE INTO 命令来实现,可以利用多台MySQL 实现高扩展性和高可用性。

在分布式系统中,如何生成分布式ID?

比如以 2 台MySQL 服务器实例,分别进行配置。

节点一配置:

auto_increment_increment = 2;

auto_increment_offset = 1;

节点二配置:

auto_increment_increment = 2;

auto_increment_offset = 2;

上述配置最好放到配置文件中,否则MySQL 服务器重启将丢失设置。

然后分别在2个库里面,建表,如tickets,设置ENGINE=MyISAM,表级锁,能保证所有 REPLACE INTO 的原子性。不断通过 REPLACE INTO 促使ID 自增,这样表中只有一条记录。

REPLACE INTO tickets (stub) VALUES ('a')

在同一个连接内,通过 last insert id 获取自增的ID 值。

Ticket Server 的优点:

  • 对于数据量不是特别大的应用场景,长度最小。
  • 如果已经有应用基于 MySQL 的自增ID,那么采用此方案非常容易迁移,而且兼容性好。

这个方案没有绝对的顺序,只能有一个近似的顺序,有可能在某个MySQL 实例的状态跑得快。

总结

如果在高并发、大数据量的情况下,建议采用 SnowFlake 方案,性能突出。

对于并非不大,并且需要兼容老业务的场景下,可以使用 Ticket Server方案,2台MySQL 物理机也能轻松达到 几万TPS,响应时间在毫秒级。


分享到:


相關文章: