0. 概述

在清理收藏夹的时候发现了一篇美团技术团队分享的关于分布式 ID 的文章,同时,最近看到他们开源了他们的实现,所以就消化了一下,原文我觉得写得有点冗长和不清晰,所以我就顺带总结了一下,内容就列举在下面吧。

总的来说,对于分布式 ID 的要求主要有以下几个方面:

  1. 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
  2. 递增性:对于分配的 ID,需要根据申请的顺序保持增序
  3. 安全性:ID 不具有完全的规律让人发现分配 ID 的数量,同时又不存在已知安全风险
  4. 高可用:不能出现无法分配 ID 的情况,或者尽可能出现的时间短(5个9以上?)
  5. 扩展性:系统性能可以扩展

然后就根据这些要求我对提及到的算法和方式进行一个归纳:

1. UUID

UUID 有多个版本,每个版本的生成方式略有不同,到目前为止,总共有 5 个版本,但是无论是哪个版本,他们的表示都是一致的,以 16 进制表示可以分为 5 组:

  1. [root@liqiang.io]# 844412
  2. [root@liqiang.io]# 8ca0fd81-fd03-438c-8730-c6c4e7ef4aa9

其中有两个特殊的位置是表示使用的 UUID 的版本的:

  1. [root@liqiang.io]# xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

不同版本生成的 UUID 的规则:

优缺点

UUID 优点:

UUID 缺点:

2. 数据库生成

通过一个设置一个 MySQL 的自增 ID 字段,每次需要 ID 的时候就从这个字段获取下一个可用的值。

数据库生成扩展

将单机的 MySQL 扩展为 MySQL 集群,总共 N 台机器,每台集群设置不同的起始 ID(0,1,2…,N-1),然后设置一样的增长步长(N),添加一层分发器材从轮询不通的机器获取下一个 ID:

3. snowflake

snowflake 是 twitter 发表的分布式 ID 算法,生成算法的方式为:

通过这种方式:

启动流程

segment-id

因为每次 ID 都从 DB 直接获取容易出现 DB 的瓶颈,所以这里的解决方案是开一个组件预取一段 ID,用于分发:

但是这个还是有以下缺点:

美团的文章只给了第 2 个的解决方案,那就是引入双层 buffer:

时钟回拨解决

我的个人看法:可以不可以在时钟回拨之后重新注册,分配一个新的 worker id?

5. 总结

从上面 3 种方案来看,twitter 的 snowflake 是一种比较好的方法,明显的缺点就只有一个了,那就是在时钟回拨的时候会出现问题。而通过 MySQL 的方案呢,主要缺点在于扩展性和性能瓶颈上,所以美团的技术团队针对这两个问题提出了两个解决方案。

这篇文章虽然没有对我们暴露所有的技术细节,但是也是了解了美团对分布式 ID 上的实践。这里还是有一些问题值得我去思考一番:

以上都是我个人的瞎猜,如果你想看关于文章的更多细节,不妨点下方的原文连接进行阅读。

6. Reference