设计分布式唯一id生成

2021-07-11  本文已影响0人  周群力

1. 生成全局唯一id

什么时候需要生成全局唯一id

db不帮你自动生成的时候。比如:

如何设计全局唯一id生成服务

a. 不依赖第三方唯一id生成服务,利用业务db的特性来生成id
比如业务的“订单表”做了分库分表后,想要全局唯一的订单id,就让分库后每个库按不同的起点和步长做递增。这样订单系统就不用依赖发号服务了,自己解决问题


image

缺点是db扩缩容时候太复杂。
另一个思路是每个分表有一个前缀,在分表内自增
这样其实可以避免扩缩容麻烦的问题,比如sharding策略是预先分1000个表,每个表的id有个通用前缀,表内id自增

b. 非中心化方案,机器标识(比如mac地址)作为命名空间,通过命名空间保证唯一
比如:

c. 中心化方案,实现一个唯一id生成服务,基于写操作线性一致的存储
比如用mysql自增特性做个发号器服务
比如随机,往线性化存储里cas写,写成功就算申请到id
如果吞吐量过大、对存储有压力,可以在存储上面加个cache,预先从存储申请多个id(号段)。这个cache就不需要用redis等,起个java程序做进程内cache即可

2. 生成“趋势递增”的全局唯一id

什么场景需要趋势递增?

select * from message order by message-id limit 100

再比如nosql之类的在时间戳字段上加索引很难,分页查最新数据的时候,只想按id查
https://www.w3cschool.cn/architectroad/architectroad-distributed-id.html

方案

Q: 类snowflake算法基于时间戳+命名空间,时钟回拨怎么办?
(发生闰秒、NTP时钟同步等情况都可能导致时钟回拨)
a. 外接存储记录最新时间戳,检测回拨。比如美团外接了个zk
b. 最终往线性化存储里写的时候检测重复,重复就报错重来
c. 多加几个命名空间,让概率小到忽略不计

Q: snowflake里的workerId咋生成
a. 基于线性化存储
比如美团方案,外接一个zk,每个机器顺序取workerId(依赖机器);
但是这样太重了,可以把workerId换成业务id,思想是通过命名空间减少冲突概率,而不是绝对唯一

b. 没必要一定用机器id,本质上只是加个命名空间,加几个业务字段作为命名空间就行
我们之前用到的方案是id里面除了时间戳还加上一些uid、业务类型、随机数之类的字段,作为命名空间,减少冲突概率

3. 生成全局单调递增的唯一id

什么场景需要

方案

Q: 分布式关系库能否自动生成全局单调递增的唯一id?
看Tidb的只是单机递增,没法保证全局单调递增:
https://docs.pingcap.com/zh/tidb/stable/auto-increment

4. 介于“趋势递增”和“全局单调递增”之间的保证

“趋势递增”和“全局单调递增”这两种保证处于两个极端,能否给出介于两者之间的保证?

Reference

架构 细聊分布式ID生成方法
Leaf——美团点评分布式ID生成系统
https://www.liaoxuefeng.com/article/1280526512029729

上一篇 下一篇

猜你喜欢

热点阅读