三 分布式 ID 微服务
从上面的分析可以看出,每种方案都各有优劣,我们现在参考美团 Leaf 方案实现自己的分布式Id。
3.1 美团 Leaf 方案实现
原 MySQL 方案每次获取 ID 都得读写一次数据库,造成数据库压力大。改为批量获取,每次获取一个 segment(step 决定大小)号段的值。用完之后再去数据库获取新的号段,可以大大的减轻数据库的压力。
————————————————
3.1.1 优点
Leaf 服务可以很方便的线性扩展,性能完全能够支撑大多数业务场景。ID 号码是趋势递增的 8byte 的 64 位数字,满足上述数据库存储的主键要求。
容灾性高:Leaf 服务内部有号段缓存,即使 DB 宕机,短时间内 Leaf 仍能正常对外提供服务。
可以自定义 max_id 的大小,非常方便业务从原有的 ID 方式上迁移过来。
3.1.2 缺点
ID 号码不够随机,能够泄露发号数量的信息,不太安全。
TP999 数据波动大,当号段使用完之后还是会在获取新号段时在更新数据库的 I/O 依然会存在着等待,tg999 数据会出现偶尔的尖刺。
DB 宕机会造成整个系统不可用。
3.1.3 优化
Leaf 取号段的时机是在号段消耗完的时候进行的,也就意味着号段临界点的 ID 下发时间取决于下一次从 DB 取回号段的时间,并且在这期间进来的请求也会因为 DB 号段没有取回来,导致线程阻塞。如果请求 DB 的网络和 DB 的性能稳定,这种情况对系统的影响是不大的,但是假如取 DB 的时候网络发生抖动,或者 DB 发生慢查询就会导致整个系统的响应时间变慢。
为此,希望 DB 取号段的过程能够做到无阻塞,不需要在 DB 取号段的时候阻塞请求线程,即当号段消费到某个点时就异步的把下一个号段加载到内存中。而不需要等到号段用尽的时候才去更新号段。这样做就可以很大程度上的降低系统的 TP999 指标。
采用双 buffer 的方式,Leaf 服务内部有两个号段缓存区 segment。当前号段已下发 10%时,如果下一个号段未更新,则另启一个更新线程去更新下一个号段。当前号段全部下发完后,如果下个号段准备好了则切换到下个号段为当前segment 接着下发,循环往复。通常推荐 segment 长度设置为服务高峰期发号 QPS 的 600 倍(10 分钟),这样即使 DB 宕机,Leaf 仍能持续发号 10-20 分钟不受影响。每次请求来临时都会判断下个号段的状态,从而更新此号段,所以偶尔的网络抖动不会影响下个号段的更新。
————————————————