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

2024-07-08 19:53:03 +08:00
 bronyakaka

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

我能想到的方案:

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

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

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

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

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

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

4289 次点击
所在节点    程序员
33 条回复
awalkingman
2024-07-08 20:14:42 +08:00
提前生成好,分发只需要查询修改。
0608516518
2024-07-08 20:18:09 +08:00
如果是绝区零这样的成熟游戏与应用,基本可以确认用的是传统 RDMS (如 MySQL )来保存账号。

不能只想着分配 id ,别忘了还用户资料、昵称、人物数据等等。这些都得有地方存啊。说来说去,还是数据库赛高。

我不那么相信 “几分钟就生成了上百万 id”,可能是之前预约用户已经分配、初始化好账号了。如果我是该产品的开发,一定会想出削峰填谷的策略。

退一万步“几分钟的百万次请求”其实也并不算大,3K QPS 情况下,5 分钟就可以生成 100w 个数据了,3K QPS 插入,在 SSD + 较多核服务器 + user 表 sharding 情况下,还是可以扛住的。但这样搞,技术风险大,压力测试也难做。想必还是用预约玩家的数据已经生成好了
killergun
2024-07-08 20:22:09 +08:00
dwu8555
2024-07-08 20:32:03 +08:00
为什么非要自增不可呢
chendy
2024-07-08 20:37:03 +08:00
不要小看了跑在高性能 SSD 上的数据库的性能啊
Ashe007
2024-07-08 20:37:40 +08:00
一、分布式 ID ( MybatisPlus 、Twitter 、美团)
二、数据库插入行为由 MQ 或线程池异步执行,避免高并发可能造成的 ID 生成问题
三、有没有好心人捞个 Java 开发
crackidz
2024-07-08 20:37:42 +08:00
@dwu8555 确实没必要,不过楼主的例子,绝区零是自增的而已
povsister
2024-07-08 20:40:59 +08:00
我猜是中心发号段+预分配。
不是来一个帐号发一次,而是一个登录服务器会预取一段号码( 1000-几万个),中心发号器只需要一段段分配就行了。

这也能解释为啥有人就是登录卡了一下,uid 直接上 100 多万了都。。

高并发系统嘛,无非就是来来回回几个方案,去中心化,批处理,异步队列。核心就是打散 IO 压力。
Ashe007
2024-07-08 20:42:26 +08:00
@Ashe007 没有看到连续递增的需求,可能需要根据 Twitter 的雪花算法稍微定制下
cheneydog
2024-07-08 20:50:58 +08:00
@0608516518 #2 楼主,qps 和 tps 是怎么理解的?生成 id 包括请求-生成-返回才算做完,我认为应该用 tps 吧。
单算 qps 请求性能不完整吧。
night98
2024-07-08 20:51:21 +08:00
都是提前分发的,不存在一个单点且可靠的高性能自增方案,A 机器领 2000 ,B 机器领 2000 号段就行了,反正最终是肯定会用完的
laminux29
2024-07-08 21:05:40 +08:00
有没有一种可能,这点数据量,什么都不用考虑,机器就能扛下来?

假设 1 分钟生成一百万个自增 ID ,平均每秒 16666 个自增 ID 。

Redis benchmark ,https://openbenchmarking.org/test/pts/redis ,i3-8100T ,每秒 123 万个 request 。

另外自从 SATA-SSD 普及以来,有没有发现,关于数据库性能的讨论,越来越少了? nvme-SSD 普及后,这类讨论几乎绝迹了。原因是,1 块正规的 SATA-SSD ,性能是 HDD 的 100 多倍,甚至 pcie5-nvme 能达到 2 千多倍。

建议学软件开发的,一定要经常关注硬件性能测试。
kenvix
2024-07-08 21:11:13 +08:00
游戏开服是一件完全可以预估到并发情况的事情,这种情况就直接按照预估去预分配就可以了
kenvix
2024-07-08 21:12:23 +08:00
@dwu8555 #4 有没有一种可能楼主是在问《绝区零是如何实现连续自增 ID 的》😅
luckyrayyy
2024-07-08 21:19:54 +08:00
我理解你以为的是:按照请求顺序,严格顺序递增。实际上不一定是这样,可能前一秒注册的比后一秒 ID 大。
ZZ74
2024-07-08 21:20:44 +08:00
很多框架啊。都是 8 楼说的那样一个服务生成一大堆,客户端每次拿一批。
0608516518
2024-07-08 22:10:44 +08:00
@cheneydog 哦严格来说确实是 TPS 。只不过站在后端视角,一个 API call 一般也就是一个 transaction 。所以 QPS 与 TPS 基本一致。

当然你可以说强调数据库写入性能时用 TPS ,强调应用服务器处理请求时,使用 QPS
lyy780808
2024-07-08 22:22:43 +08:00
不是严格递增的话,数据库主键自增性能也是够的,可以多部署几个数据库实例进行分片,然后写一个提前生成 id 的功能应对开服流量。
cowcomic
2024-07-08 22:26:08 +08:00
通常不会用 redis ,正常的时候没问题,万一出了问题,就是大问题,这个风险不敢赌
最好就是关系型数据库,通常就是 ID 分段,用个表管理 ID 段(这个表里可以根据预期预设好),每个实例已有段用完了就拿新的,段内自己做自增,万一故障恢复所需要校验的也不多
这样无法严格保证一定是小先大后(只要一个段不是特别宽,也很难察觉到),但基本能保证连续,没有跳号
这样缩容扩容也简单,无脑加减机器就行(严格连续的话,减机器是要做处理的)
zhangk23
2024-07-08 23:19:47 +08:00
不太可能是实时自增,要我做我肯定是号段分配的,根据地区百分比做服务器权重分发

甚至我缺德一点给预约玩家提前分一个靠前号段的 id (

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

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

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

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

© 2021 V2EX