如何在服务端做大量的用户自定义的定时任务

2021-02-07 11:29:42 +08:00
 chanlk

场景说明:

iot 设备, 设备自身不支持定时的功能, 需要服务端根据用户指定的规则下发指令到设备

举个栗子:

下面是我的尝试, 不知道这个思路有什么坑 [-_-||]

我的思路:

​ 利用 redis pub/sub 与 redis expired 功能;

具体实现:

  1. 将用户设置的定时规则先存入表;
  2. 从用户存入规则中取出最近将要执行的一条任务;
  3. 计算出该任务过期时间然后将任务存入 redis;
  4. 监听 redis 过期事件, 当有过期事件发生时, 执行该任务;
  5. 重复 2 -> 3 -> 4;

我认为会遇到的坑:

  1. 大量过期 key 同时到期会有性能问题吗?
  2. 集群部署同时监听过期事件如何避免重复执行?
  3. 用户随时可增删改规则,感觉我会写出 bug 来...
  4. 用户时区问题,以及夏令时冬令时问题.

经验丰富的大佬们有空帮忙瞅瞅这个设计有什么缺陷吗?

PS: 这种活讲道理确实设备端做比较合适吧

2174 次点击
所在节点    问与答
17 条回复
chanlk
2021-02-07 11:31:03 +08:00
排版乱了, 我排个版面先, 辣到各位眼睛了, sorry
xlui
2021-02-07 12:27:42 +08:00
服务端定时任务就可以了吧,没看懂 redis 这一层做了什么
yejianmail
2021-02-07 12:31:10 +08:00
是的,你都扫描数据库的表了还要 redis 干啥,你这都可以直接扫出到期的任务了,你这场景应该属于消息中间件干的活
matrix67
2021-02-07 12:32:07 +08:00
估算一下服务端并发下发指令的 qps 就行
renyijiu
2021-02-07 12:43:38 +08:00
redis 的不是可靠的消息消费,想想业务能够容忍没有触发吗
cyaki
2021-02-07 12:45:34 +08:00
如果使用 Redis pub/sub, 监听程序重启 /升级过程中,会漏掉在这期间下发的消息
chanlk
2021-02-07 13:49:51 +08:00
@xlui @yejianmail 你们的意思是说建定时任务不断的读表, 然后找到表中当前需要执行的任务直接遍历就去执行吗?
wizzer
2021-02-07 13:53:13 +08:00
定时任务比如 quartz xxl-job 本身就可以了
jybox
2021-02-07 13:55:24 +08:00
设计基于 Redis 的定时任务系统( ZSET + Scripting )
https://jysperm.me/2019/08/redis-cronjob-system/
godlovesxcjtest
2021-02-07 13:55:35 +08:00
用延迟消息队列啊,这个最合适了
justfun
2021-02-07 13:57:20 +08:00
@xlui 建议了解下为什么有"队列"这个需求
wbf1013
2021-02-07 15:08:19 +08:00
消息队列就完事了
zoharSoul
2021-02-07 15:14:44 +08:00
扫表, 或者消息队列都行
cyaki
2021-02-07 15:33:31 +08:00
@chanlk 用户提交定时任务后,可以再修改任务的执行时间吗
chanlk
2021-02-07 15:36:25 +08:00
@cyaki 可以, 用户的定时任务增删改查都是开放的, 随时可以进行操作
chanlk
2021-02-07 16:46:50 +08:00
@wizzer 我看了一下 quartz 这类相关的定时调度轮子, 包括 quartz xxl-job elastic job 等, 对于动态添加定时任务都是没有做原生的支持, 网上博客都是自己做了一些别的封装调用的. 再结合 quartz 的工作原理(有一个轮训所有 Trigger 的动作), 我认为这些定时任务框架是不适合我的场景的.

我的场景是大量功能相同的任务, 在不同时间点触发;
而 quartz 之类的一般都是做一些后台任务, 比如定期删删数据库的老数据, 做备份什么的;
tongz
2021-02-07 16:56:10 +08:00
PHP 可以直接用 Laravel 的 schedule 实现

他的实现逻辑是 crontab 加个 * * * * *, 程序中定义执行周期, 每分钟会扫描所有程序中定义的 schedule, 遇到当前应该执行的任务就会做执行动作, 所以举个例子: $schedule->call(xxx)->dailyAt($customCron);

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

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

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

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

© 2021 V2EX