# 《分布式IM系统》通用模型-第07节:分布式ID生成器的设计与实现

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)
课程视频:https://t.zsxq.com/15NxGhnII (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本节难度:★★☆☆☆
  • 本节重点:多分布式ID生成器进行设计与实现,了解常用的分布式场景下的ID生成方案,并掌握其核心原理与优缺点,能够在实际场景下根据自身实际业务选择符合自身业务场景的分布式ID方案,并能够将其灵活应用到自身实际项目中。
  • 课程视频:https://t.zsxq.com/15NxGhnII (opens new window)

大家好,我是冰河~~

在分布式场景下,数据库中的自增ID不再适用。此时,就需要我们思考如何在分布式场景下实现数据的ID属性。还好业界已经提供了很多的实现方案,不用我们自己再重复造轮子了。

# 一、前言

在分布式IM即时通讯系统中,不管是用户的基础信息、群组数据,还是好友之间的关系数据,亦或是分布式IM即时通讯系统中的消息数据,都需要一个全局唯一并且有序的ID来唯一标识相关的数据。数据库自增主键倒是能满足在单机场景下的有序性,但是在分布式场景下就不太适用了。

# 二、本节诉求

考虑到分布式场景下数据的全局唯一与有序性,对分布式ID生成器进行设计与实现。重点掌握雪花算法的实现原理,并能够将其灵活应用到自身实际项目中。

# 三、分布式ID方案

在分布式系统中,为了唯一标识不同的数据或者对象,需要生成全局唯一的ID。分布式ID是指在分布式环境下,生成的全局唯一的ID。

在传统的单机环境下,在向数据库插入数据时,可以无需指定ID数据,直接使用数据库自增ID即可。但是在分布式环境下,这些方式不再适用,因为分布式系统可能包含多个节点,每个节点都独立生成ID会导致冲突和重复。因此,分布式ID需要考虑以下几个问题:

  • 全局唯一性:在整个分布式系统中,每个ID都应该是唯一的。
  • 有序性:ID应该具有一定的有序性,以便于排序和查询。
  • 低延迟:ID的生成速度应该足够快,不能成为系统的瓶颈。
  • 可扩展性:系统应该支持水平扩展,能够容纳更多的节点和请求。

目前,常见的分布式ID方案包括雪花算法、基于数据库自增ID、基于数据库分区的ID、基于ZooKeeper的全局唯一ID等。

  • 雪花算法(Snowflake):雪花算法是一种经典的分布式ID生成算法,它由Twitter开发并开源。它使用一个64位的整数作为ID,可以根据时间戳、机器ID和序列号来生成唯一的ID。这种方案简单、高效,并且具备良好的有序性。
  • 基于数据库自增ID:在分布式系统中,可以使用数据库的自增ID来生成唯一ID。每个节点从数据库中获取一个唯一的ID,然后进行操作。这种方案依赖于数据库的性能和可用性,但是实现相对简单。
  • 基于数据库分区的ID:在分布式系统中,可以将ID的生成和存储分散到不同的数据库分区上。每个分区使用不同的ID生成策略,例如使用数据库自增ID、雪花算法等。这样可以提高性能和并发度,减少单点故障的影响。
  • 基于ZooKeeper的全局唯一ID:ZooKeeper是一种分布式协调服务,可以用于生成全局唯一的ID。每个节点通过竞争创建ZooKeeper的顺序节点来获得唯一的ID。这种方案依赖于ZooKeeper的性能和可用性,但可以保证全局唯一性。
  • 基于UUID:UUID(Universally Unique Identifier)是一种128位的标识符,几乎可以保证全球范围内的唯一性。在分布式系统中,可以使用UUID来生成唯一ID。这种方案简单、无需中心化服务,但是UUID较长且无序。

# 四、雪花算法

雪花算法(Snowflake)是一种经典的分布式ID生成算法,它由Twitter开发并开源。雪花算法使用一个64位的整数作为ID,可以根据时间戳、机器ID和序列号来生成唯一的ID。具体的实现原理如下:

  • 时间戳部分记录了当前时间与计算机元年(1970年1月1日)的差值,精确到毫秒级别。
  • 机器ID是一个固定的数字,通常可以根据IP地址或者MAC地址等信息来生成。
  • 序列号是在同一毫秒内并发生成多个ID时使用的,可以用来保证ID的唯一性和有序性。
  • 在同一毫秒内,序列号会自增,当序列号达到最大值后,会等待下一毫秒再继续生成ID。
  • 如果在同一毫秒内有多个线程或进程同时生成ID,会通过竞争机制来获取序列号,保证唯一性。

接下来,看一下雪花算法生成的64位ID的结构,如图7-1所示。


  • 1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。
  • 41bit时间戳,毫秒级。可以表示的数值范围是 (2^41-1),转换成单位年则是69年。
  • 10bit工作机器ID,用来表示工作机器的ID,包括5位datacenterId和5位workerId。
  • 12bit序列号,用来记录同毫秒内产生的不同id,12位可以表示的最大整数为4095,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。

# 五、编码实现

# 查看完整文章

加入冰河技术 (opens new window) 知识星球,解锁完整技术文章、小册、视频与完整代码