讨论下高并发、连续自增的 id 的生成方案

132 天前
 bronyakaka

最近玩绝区零,才开服几分钟就生成了上百万 id ,而且是连续递增的( 1->2->3->4 这种),不知道是怎么实现的。

我能想到的方案:

1 、redis string incr 递增,redis 本身线程安全,感觉这个方案可行,就是不知道 qps 有没有 1w 。而且引入 redis 可能不太稳定?并发量十万会不会直接打崩或者阻塞(刚开服瞬间我感觉有这个并发量)。

2 、雪花 id ,这个肯定不是上面游戏生成的方案,因为雪花 id 不是连续的,不过雪花 id 的 qps 非常高

3 、给 int 整型加锁,原子化操作,并发是安全的,但是这个就不是分布式了,有单点故障问题,而且 qps 也难说

4 、本地缓存?纯本地内存操作,加个读写锁,不知道性能怎么样,也有单点故障问题。、

5 、数据库自增主键?性能应该不够吧

有经验的懂哥能否讲解一下

3507 次点击
所在节点    程序员
33 条回复
wushenlun
131 天前
提前生产 1000w 个,如果余额不够 1000w 就补足到 1000w 。新用户来就直接分配,用不着实时生成
lazyfighter
131 天前
5 分钟 1000w , 每秒钟 tps 是 33333 , 假设 16 张表,每秒 2000 ,如果还多 2 个 mysql 实例,每秒 1000 , 还觉得多再拆表*2 , 每秒钟 500
diagnostics
131 天前
广告新思路?好几个《绝区零》的帖子了
y830CAa5nink4rUQ
131 天前
用 MySQL 的话,有内置的顺序 ID 生成器,非常好用:

SELECT uuid_short() AS id;

这个内置 ID 生成器性能非常屌,也不用担心 ID 生成器会挂导致所有服务受影响,因为当你数据库都挂了,那么你什么都挂了。

这个生成器我目前发现唯一的缺点:有部分云厂商的定制化 MySQL 会返回 19 位的数字,刚刚好超出 Java 里 long 的范围(因为 Java 没有 unsigned ,最数字是 9,223,372,036,854,775,807 )。
chutianyao
131 天前
1. REDIS 单实例写 ops 扛 1w 毫无压力, 正常 key 分散的情况下 5-6w 应该可以, 但这种热 key 不确定
2.预计就是实现了一个 id 生成器, jvm 中预先分配号段, 我之前实现过, 这种简单的接口单机扛百万 qps 毫无压力
sunny352787
131 天前
我问下啊,是怎么确定的这个 ID 是连续的呢?
cloudzhou
131 天前
kv 支持下(比如 redis 效率已经很高了),需要中间件配合,设计思路如下:

1. 不是每次 incr 1 ,而是每次 incr step ,比如 +1000 ,那么就有 (X, X + 1000] 这个区间都可使用

2. step 的计算方式如下,比如设计成最多 T 时间,incr step ,运行中一直调整 step

3. 初始状态:step 初始化为 1 ,T 举个例子:1s ,变化倍数 rate: 2

4. 那么,1s 内如果多次 incr step ,那么 step = step * 2 ,让 step 尽量变长,尽量超过 1s

5. 当 incr step 间隔时间超过 2s ,那么 step = step / 2 ,让 step 尽量变小,尽量靠近 1s

6. 在 4/5 结合之下,step 将把 qps 接近 1s ,上下徘徊,算法可以微调

缺点:

重启的时候,会丢弃一些 id ,这个也可以细节改进,比如把未使用的 id 返回给 redis
cloudzhou
131 天前
另外一种就是选举领号,设置总分片 X (比如 1000 )
每个进程都注册 zookeeper ,etcd ,所以总进程是可知的,根据进程数量,可以知道每个进程可占据的分片

那么,假设完美情况 100 个进程,那么每个进程分配 10 个分片([0-10), [10, 20)...)

占据 0 分片,每次产生 0 ,10 ,20 ,30...
占据 1 分片,每次产生 1 ,11 ,21 ,31...

本地保持状态即可,依赖选择竞争分片
----

以上两个算法,id 增长,但是 id 本身不能体现先后顺序。
skuuhui
131 天前
最简单的就是提前生成好塞队列。
另一种类似多台 id 发放器,生成不同片的 id (单数,双数,末尾是 1 ,2,3 的),虽然他们严格上不连续,但在短时间内并发过程中是连续的。
就算最差的实现方式都可以用逻辑优化。
esee
131 天前
就算只用 mysql ,自增 id 5 分钟跑 100 万 完全轻轻松松啊,你自己搭个 mysql 试一下 5 分钟能插入多少就知道了。mysql 的经验在好的硬件面前已经跟不上了,一块 4k 性能好的 ssd 顶 10 个 dba 不是开玩笑。
keepme
131 天前
如果不是非按严格的顺序自增的话,雪花 id 就行了吧,本地直接生成
PiersSoCool
131 天前
你们是不是低估了 MySQL 的性能,几分钟几百万个请求,算什么垃圾
kakawa
129 天前
每个公司都有自己的发号器服务吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1055762

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX