京东一面:分布式 ID 生成方案怎么选?写得太好了!
共 1934字,需浏览 4分钟
·
2022-04-10 18:28
点击关注公众号,Java干货及时送达
背景
在分布式系统中,经常需要用到全局唯一ID发生器,标识需要存储的数据。我们需要什么样的ID生成器?
ID生成器除了是数据的唯一标识以外,一般需要在系统中承担更多的责任,概括起来有以下几点。另外,分布式系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。
唯一性:“全局唯一” vs “业务唯一”?
分布式系统使用唯一的ID生成器,会有非常严重的申请互斥问题。互斥加锁意味着成本和性能的下降,不容易去实现一个高性能高可靠的架构。在业务系统中,往往也不需要全局唯一的ID。
比如在通讯系统里,聊天消息不需要全局唯一,标识一条用户发出的消息的ID,只要保证用户唯一性即可。因为消息本身归属于某一用户,因此用户唯一已经隐含了“全局唯一ID ( = 用户ID + 消息ID )”。
时间相关:“秒级” vs “毫秒”?
有序:“粗略有序” vs “精确有序”?
首先,如果要达到精确的有序,就要对 Sequence 进行并发控制,性能上肯定会打折。其次,同一时间只能生成一个ID,意味着同一时间只有一个ID生成服务实例可以提供服务,精确有序还会面临容灾问题。
设计细节
看下业界如何设计ID发生器。另外,想成为架构师,这份架构师图谱建议看看,少走弯路。
SnowFlake
41bit留给毫秒时间,10bit给机器 (MachineID) ,剩下12bit留给Sequence。
Flicker
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
Flicker启用了两台数据库服务器生成ID来容灾,通过区分auto_increment的起始值和步长来生成奇偶数的ID。
TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1
TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2
微信
微信使用MySQL持久化未分配的最大ID,每次从DB取一段放到内存分配给调用方。微信的ID生成是严格递增的,意味着同一时间只能有一台机器提供服务,因此使用仲裁服务+租约机制+路由表,进行容灾。
Shopee Feeds 如何生成ID ?
考虑到Feeds业务的特性,并不需要精确有序,因此我们使用snowflake算法进行ID生成。使用39 (毫秒)+ 5(机器) + 9(seq),来保证ID作为Redis的score不会溢出。最新面试题整理好了,大家可以在Java面试库小程序在线刷题。
Redis 有序集合的分数使用双精度64位浮点数, 表示为一个IEEE 754 floating point number,它能包括的整数范围是-(2^53) 到 +(2^53)
这样的ID生成器可以使用大约17年,对于一款产品的生命周期来说已经足够使用。
针对时间回拨产生的问题,因为发生的频率极小,所以只需要简单判断,如果不满足 currentMillis <= lastTime,则返回错误即可。
作者:cyningsun
来源:www.cyningsun.com/12-26-2018/id-generator.html