前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >架构师如何高效管理100w+定时事件???(第30讲)

架构师如何高效管理100w+定时事件???(第30讲)

作者头像
架构师之路
发布2025-01-02 18:15:39
发布2025-01-02 18:15:39
1170
举报
文章被收录于专栏:架构师之路架构师之路

《架构师之路:架构设计中的100个知识点》 30.海量定时事件管理

什么场景会用到海量定时事件?

例如:有100W个用户uid在线接单,客户端每30s会有一个存活上报,如果30s没有上报,服务端要将用户的状态置为不可接单。

一般如何怎么实现这类需求?

大体来说,有三类方法:

方案一:轮询扫描法。

1. 用一个Map<uid, last_time>来记录每一个uid最近一次上报时间;

2. 当某个用户uid存活上报时,实时更新这个Map;

3. 启动一个timer,轮询扫描这个Map,看每个uid的last_time是否超过30s,如果超过则进行超时处理;

这个方案的特点是:只启动一个timer,但要轮询,CPU会跑满,比较消耗计算资源。

方案二:多timer触发法。

1. 还是用一个Map<uid, last_time>来记录每一个uid最近一次上报时间;

2. 当某个用户uid存活上报时,实时更新这个Map,并同时对这个uid启动一个timer,30s之后触发;

3. 每个uid请求包对应的timer触发后,看Map中,查看这个uid的last_time是否超过30s,如果超过则进行超时处理;

这个方案的特点是:不需要轮询,但每次上报都要启动一个timer,timer的维护量在100w级别,比较消耗内存资源。

方案三:环形队列法。

1. 30s超时,就创建一个index从0到30的环形队列(本质是个数组);

2. 环上每一个slot是一个Set<uid>,表示在这一秒钟,这些uid触发过存活上报;

3. 同时还有一个Map<uid, index>,记录uid落在环上的哪个slot里;

4. 启动一个timer,每隔1s,在上述环形队列中移动一格,0->1->2->3…->29->30->0…;

5. 有一个Current Index指针指向正在检测的slot;

那怎么记录last-time呢?

不用记录last-time了,每当报文上报,就将原来的uid删除,重新加入到当前指针的前一个slot。

为什么是前一个slot?

因为前一个slot将在30s之后被扫描到。如果uid按时上报了,它将永远不会被扫描到。只有30s内没有上报,才会被扫描到。

这个方案的特点是:

1. 只有一个timer,不耗内存资源;

2. 不是for循环轮询,而是每1s钟走一格,不耗CPU资源;

3. 当前指针扫描到的slot里的Set<uid>批量超时,业务处理块;

另外,这个环形队列法是一个通用的方法,Set和Map中可以是任何task,本文的uid是一个最简单的举例。

环形队列法,还有其他场景使用吗?

HashedWheelTimer也是类似的原理。

知其然,知其所以然。

思路比结论更重要。

补充阅读材料:

《HashedWheelTimer》

https://dev.to/frosnerd/hashed-wheel-timers-5bo9

文章不长,含代码解析。

==全文完==

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构师之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档