admin管理员组

文章数量:1444613

架构师究竟要不要懂细节?分布式ID生成的6种方法(第45讲)

《架构师之路:架构设计中的100个知识点》

45.分布式ID生成

几乎所有的业务系统,都有生成一个唯一记录标识的需求,例如:消息ID,订单ID,帖子ID...

这个ID,在数据库中往往用作主键,且有排序与分页的查询需求。这也是分布式ID生成算法的两大核心需求:

1. 全局唯一;

2. 趋势递增;

如何高效生成趋势有序的全局唯一ID,是每一个工程师都会遇到的问题。

方法一:数据库auto-inc-id法

借助数据库的auto_increment来生成全局唯一递增ID。

优点:

1. 简单,使用数据库已有的功能;

2. 能够保证唯一性;

3. 能够保证递增性;

4. 步长固定;

不足:

1. 可用性难以保证,需要依赖数据库的高可用;

2. 扩展性差,性能有上限,数据库主库的写性能决定ID的生成性能上限;

改进方法:

1. 冗余主库,避免写入单点;

2. 数据水平切分,保证各主库生成的ID不重复;

改进后,数据库的写压力依然很大,每次生成ID都要访问数据库。为了解决这个问题,引出了第二个常见的方案。

方法二:批量ID生成服务

数据库写压力大,是因为每次生成ID都访问了数据库,可以使用批量的方式降低数据库写压力。

ID生成服务假设每次批量拉取6个ID,服务访问数据库,将当前ID的最大值修改为5,这样应用访问ID生成服务索要ID,ID生成服务不需要每次访问数据库,就能依次派发0,1,2,3,4,5这些ID了。

当ID发完后,再将ID的最大值修改为11,就能再次派发6,7,8,9,10,11这些ID了,于是数据库的压力就降低到原来的1/6。

优点

1. 保证了ID生成的绝对递增有序;

2. 大大的降低了数据库的压力,ID生成可以做到每秒生成几万几十万个;

同时,服务也可以做集群化,只是稍微要注意数据一致性问题,具体CAS优化方案在《巧用CAS实现分布式ID生成器!(43)》中有详细介绍,不再展开。

方法三:uuid/guid法

不管是通过数据库,还是通过服务来生成ID,业务方都需要进行一次远程调用,比较耗时。有没有一种本地生成ID的方法,即高性能,又时延低呢?

uuid是一种常见的方案:

代码语言:javascript代码运行次数:0运行复制
string ID =GenUUID();

优点

1. 本地生成ID,不需要进行远程调用,时延低;

2. 扩展性好,基本可以认为没有性能上限;

不足

1. 无法保证趋势递增

2. uuid过长,往往用字符串表示,作为主键建立索引查询效率低,常见优化方案为“转化为两个uint64整数存储”。

方法四:取当前毫秒数

uuid是一个本地算法,生成性能高,但无法保证趋势递增,且作为字符串ID检索效率低,有没有一种能保证递增的本地算法呢?

取当前毫秒数是一种常见方案:

代码语言:javascript代码运行次数:0运行复制
uint64 ID = GenTimeMS();

优点

1. 本地生成ID,不需要进行远程调用,时延低;

2. 生成的ID趋势递增;

3. 生成的ID是整数,建立索引后查询效率高;

缺点:如果并发量超过1000,会生成重复的ID。

当然,使用微秒可以降低冲突概率,但每秒最多只能生成1000000个ID,再多的话就一定会冲突了,所以使用微秒并不从根本上解决问题。

方法五:类snowflake算法

snowflake是twitter开源的分布式ID生成算法,其核心思想为,一个long型的ID:

1. 41bit作为毫秒数;

2. 10bit作为机器(服务)编号;

3. 12bit作为毫秒内序列号;

算法单机每秒内理论上最多可以生成1000*(2^12),也就是400W的ID,1024台机器(服务)每秒能生活40Y的ID,完全能满足业务的需求。

借鉴snowflake的思想,结合公司的业务逻辑和并发量,可以实现自己的分布式ID生成算法

举例,假设某公司ID生成的需求如下:

1. 单机高峰并发量小于1W,预计未来10年单机高峰并发量小于10W

2. 有2个机房,预计未来10年机房数量小于4个

3. 每个机房机器数小于100台;

4. 目前有5个业务线有ID生成需求,预计未来业务线数量小于10个;

5. …

我们应该怎么来设计公司独特的ID生成算法呢?

其一,毫秒位数考虑。

假设系统至少运行10年,那至少需要10年*365天*24小时*3600秒*1000毫秒=320*10^9,差不多预留39bit给毫秒数。

其二,1毫秒内序列号考虑。

每秒的单机高峰并发量小于10W,即平均每毫秒的单机高峰并发量小于100,差不多预留7bit给每毫秒内序列号。

其三,机房数少于4个,预留2bit给机房标识。

其四,每个机房机器小于100台,预留7bit给每个机房内的服务器标识。

其五,业务线小于10个,预留4bit给业务线标识。

这样设计的64bit标识,可以保证:

1. 每个业务线、每个机房、每个机器生成的ID都是不同的;

2. 同一个机器,每个毫秒内生成的ID都是不同的;

3. 同一个机器,同一个毫秒内,以序列号区区分保证生成的ID是不同的;

4. 将毫秒数放在最高位,保证生成的ID是趋势递增的;

以上,希望大家有收获。

知其然,知其所以然。

思路比结论更重要。

扩展阅读:

==全文完==

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-03-20,如有侵权请联系 cloudcommunity@tencent 删除服务架构师算法数据库分布式

本文标签: 架构师究竟要不要懂细节分布式ID生成的6种方法(第45讲)