0. 概述
在清理收藏夹的时候发现了一篇美团技术团队分享的关于分布式 ID 的文章,同时,最近看到他们开源了他们的实现,所以就消化了一下,原文我觉得写得有点冗长和不清晰,所以我就顺带总结了一下,内容就列举在下面吧。
总的来说,对于分布式 ID 的要求主要有以下几个方面:
- 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。
- 递增性:对于分配的 ID,需要根据申请的顺序保持增序
- 安全性:ID 不具有完全的规律让人发现分配 ID 的数量,同时又不存在已知安全风险
- 高可用:不能出现无法分配 ID 的情况,或者尽可能出现的时间短(5个9以上?)
- 扩展性:系统性能可以扩展
然后就根据这些要求我对提及到的算法和方式进行一个归纳:
1. UUID
- G:
- 全局唯一得到满足
- 隐蔽性得到满足
- 无需依赖,直接生成,高可用得到满足
- 无需扩展,扩展性得到满足
- B:
- 长度太长,不适合传输和存储,MySQL 下 InnoDB 索引不友好
- 递增性无法得到满足
- 安全性方面存在一些一致风险
2. 数据库生成
通过一个设置一个 MySQL 的自增 ID 字段,每次需要 ID 的时候就从这个字段获取下一个可用的值。
- G:
- 全局唯一性得到满足
- 递增性得到满足
- B:
- 安全性无法满足
- 非高可用,MySQL 单机宕机之后服务不可用
- 无法扩展,系统性能瓶颈在 MySQL 单机
2.1 数据库生成扩展
将单机的 MySQL 扩展为 MySQL 集群,总共 N 台机器,每台集群设置不同的起始 ID(0,1,2…,N-1),然后设置一样的增长步长(N),添加一层分发器材从轮询不通的机器获取下一个 ID:
- G:
- 全局唯一性得到满足;
- 递增性得到满足
- 高可用得到满足
- B:
- 高可用和全局递增性无法同时满足;
- 扩展性不佳;
- 系统瓶颈还是在于 MySQL 瓶颈
3. snowflake
snowflake 是 twitter 发表的分布式 ID 算法,生成算法的方式为:
- 前面 41 位长的时间序列,可以精确到毫秒
- 中间 10 位的机器标识,最多支持部署1024个节点
- 后面 12 位的序列号,支持每个节点每毫秒产生 4096 个ID序号
通过这种方式:
- G:
- 全局唯一性得到满足;
- 递增性得到满足(单机递增,全局不递增)
- 高可用得到满足;
- 扩展性得到满足;
- B:
- 依赖于系统时钟,在系统时钟出现回拨的时候会出现 ID 重复;
4. 小结
从上面 3 种方案来看,twitter 的 snowflake 是一种比较好的方法,明显的缺点就只有一个了,那就是在时钟回拨的时候会出现问题。而通过 MySQL 的方案呢,主要缺点在于扩展性和性能瓶颈上,所以美团的技术团队针对这两个问题提出了两个解决方案。
snowflake
segment-id
因为每次 ID 都从 DB 直接获取容易出现 DB 的瓶颈,所以这里的解决方案是开一个组件预取一段 ID,用于分发:
但是这个还是有以下缺点:
- ID号码不够随机,能够泄露发号数量的信息,不太安全。
- TP999数据波动大,当号段使用完之后还是会hang在更新数据库的I/O上,tg999数据会出现偶尔的尖刺。
- DB宕机会造成整个系统不可用。
美团的文章只给了第 2 个的解决方案,那就是引入双层 buffer:
5. 总结
这篇文章虽然没有对我们暴露所有的技术细节,但是也是了解了美团对分布式 ID 上的实践。这里还是有一些问题值得我去思考一番:
- 有没有更好的方式能满足高性能和足够扩展性的全局递增的 ID 分配?
- DB 宕机会造成整个系统不可用,这个对于美团真的是问题吗?还是说这个可以由 DBA 团队来满足;
- 需要用 DB 去做 ID 分配这个轻的活吗?还是可以直接自己写个组件?
以上都是我个人的瞎猜,如果你想看关于文章的更多细节,不妨点下方的原文连接进行阅读。