详细提问:
目前已启用的解决办法:
Redis 开启 Key 失效 Event,服务以长连接监听事件推送。
考虑到意外,DB 也构建了一张“任务表”,用于存储任务结束时间戳,玩家每次登录时,检测存在的时间戳数据,如果有,则自动执行并清理时间戳数据( Redis 回调时,也会清理时间戳数据)。
1
Jooooooooo 2021-07-06 20:26:46 +08:00 1
延迟任务就是有个系统在帮忙轮询
一个简单的做法是把每一秒当成一个 key, 任务挂在这个 key 上, 然后弄个系统用比如 100ms 的速度去轮询这个 key, 发现上面有任务就用消息触发 |
2
qq316107934 2021-07-06 20:38:34 +08:00 1
把任务按照时间顺序插入一个有序列表中,每隔 N 段时间扫描列表头,发现到了时间就出列读下一个。如果任务很多的话可以把任务按照时间段分块插入
上述内容都可以用 redis 实现 你用发布订阅的话,可能留坑 |
3
uiosun OP @Jooooooooo 大佬,所有新增任务都挂在对应的 key 的已有 value 后面,用符号分割,每分钟查询对应 60 秒的任务,批量执行应该就可以?!我去试试
@qq316107934 大佬,如果 Redis 宕机了,又没有开持久化,这部分数据是不是就没了?当前情况下,只能靠那个 DB 的方式去救火😂 |
4
uiosun OP |
5
Jooooooooo 2021-07-06 21:07:37 +08:00 1
|
6
EscYezi 2021-07-06 21:16:03 +08:00 via iPhone 1
尝试一下延时队列?比如 rabbitmq (用的不多但是有这个功能)
|
7
qq316107934 2021-07-06 21:16:31 +08:00 1
@uiosun #3 可以写日志,出了问题回扫日志;如果不想离线扫,需要加上 DB/Redis 双写,检测到 Redis 宕机数据源就切换到 DB,然后定时 where 开始执行时间戳 < 现在时间 + 扫描时间间隔,效果一样的,但要注意 Redis 和 DB 间的任务状态同步。
|
8
CEBBCAT 2021-07-06 21:44:59 +08:00
也没有考虑过延时队列?比如楼上说的 rabbitmq 或者 beanstalk ?
听起来这个 Y 任务也有一点意思,因为赶路是需要占据时间的吧? |
9
crystom 2021-07-06 21:48:05 +08:00
redis 专门搞个消费者取 zset,生产者则用 zset 分数存时间和任务
|
10
akira 2021-07-06 22:18:45 +08:00 1
dau 1.5w ,每个用户假设每天是 10 个任务,每日总任务数量大约是 15w
做个数据表,待记录执行时间,任务编号,执行标记 以及其他必要信息, 然后定时器一直扫就好了。 再做个定期清理 足够了 |
11
woolong800 2021-07-06 22:20:07 +08:00
延迟队列吧,可以用 rabbitmq,或者自己基于 redis 的 sorted set 写一个
|
12
triptipstop 2021-07-06 23:30:22 +08:00
时间轮
|
13
Rocketer 2021-07-07 02:36:12 +08:00 1
标准做法是死信队列。
具体来说就是,把队列的超时处理方式设为转移至另一个队列(这就是所谓的死信队列),然后任务入队时设置超时(就是需要的延时)。 这样任务需要执行时就会因为超时而自动进入死信队列,你的任务执行程序从死信队列里取就行了。这样做的好处是纯异步,即使需要执行的任务突然来了很多也不怕,有死信队列帮你削峰呢。 |
14
aguesuka 2021-07-07 09:15:25 +08:00
HashedWheelTimer 的算法可以在允许少量误差的情况下实现 O(1) 级别的定时任务的插入, 删除, 和弹出.
|
15
Alexf4 2021-07-07 10:06:55 +08:00
用 celery 任务的 eta 参数,可以了解下
|
16
cctrv 2021-08-20 13:20:07 +08:00 via iPhone
Crontab 以每 1 小時定義執行一個指定腳本(你的程序)
然後,這個程序可以讀取到之前的安排的任務,判斷是否滿足執行條件,並開始處理。 |