V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
chanlk
V2EX  ›  问与答

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

  •  
  •   chanlk · 2021-02-07 11:29:42 +08:00 · 1986 次点击
    这是一个创建于 1145 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景说明:

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

    举个栗子:

    • 周一至周五,早上 8 点半将报警防御功能打开[出门打工了], 周六周日不用
    • 周一至周五,早上 11 点半将电饭锅打开, 中午 12 点半将电饭锅设置为保温, 周六周日不用

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

    我的思路:

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

    具体实现:

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

    我认为会遇到的坑:

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

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

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

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

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

    他的实现逻辑是 crontab 加个 * * * * *, 程序中定义执行周期, 每分钟会扫描所有程序中定义的 schedule, 遇到当前应该执行的任务就会做执行动作, 所以举个例子: $schedule->call(xxx)->dailyAt($customCron);
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2712 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 15:41 · PVG 23:41 · LAX 08:41 · JFK 11:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.