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

101 天前
 bronyakaka

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

我能想到的方案:

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

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

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

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

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

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

3441 次点击
所在节点    程序员
33 条回复
awalkingman
101 天前
提前生成好,分发只需要查询修改。
0608516518
101 天前
如果是绝区零这样的成熟游戏与应用,基本可以确认用的是传统 RDMS (如 MySQL )来保存账号。

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

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

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

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

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

假设 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
101 天前
游戏开服是一件完全可以预估到并发情况的事情,这种情况就直接按照预估去预分配就可以了
kenvix
101 天前
@dwu8555 #4 有没有一种可能楼主是在问《绝区零是如何实现连续自增 ID 的》😅
luckyrayyy
101 天前
我理解你以为的是:按照请求顺序,严格顺序递增。实际上不一定是这样,可能前一秒注册的比后一秒 ID 大。
ZZ74
101 天前
很多框架啊。都是 8 楼说的那样一个服务生成一大堆,客户端每次拿一批。
0608516518
101 天前
@cheneydog 哦严格来说确实是 TPS 。只不过站在后端视角,一个 API call 一般也就是一个 transaction 。所以 QPS 与 TPS 基本一致。

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

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

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

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

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

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

© 2021 V2EX