V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
moell
V2EX  ›  程序员

动态添加规则的定时任务处理,除了自己实现一个时间轮的计时器,有成熟的开源产品吗?

  •  
  •   moell · 162 天前 · 1416 次点击
    这是一个创建于 162 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    用于用户自主创建定时任务,规则存储到 Redis 或者 MySQL, 服务端根据规则定时处理

    目前的想法

    自己实现一个时间轮,秒为单位或 100 毫秒为单位

    自己实现的主要疑问

    • 如果单机的情况下,用户会集中在某个时刻执行任务,当前卡槽相对应的队列数据比较多,我将数据推送到队列中异步消费,队列繁忙时,时效性是个问题,用户体验不好。
    • 极端的情况下,可能存在用户在每秒都重复执行某个任务,那么任务都存放每个卡槽中,我感觉不合理,有更优的解决办法吗?

    了解过 xxl-job ,我觉得不适合我的场景,不知道理解是否有误,求指点。

    34 条回复    2023-09-20 14:14:39 +08:00
    burymme11
        1
    burymme11  
       162 天前
    根据你的 title ,从数据库/缓存里面拉最新的规则,解析成 cron 表达式,再去修改定时 job 的 cron ,xxl-job 可以满足啊。
    你觉的哪里不适合?
    dlmy
        2
    dlmy  
       162 天前
    xxl-job 可以满足你的需求,可以仔细看看 xxl-job 调度中心的 JobScheduleHelper 的业务逻辑。

    里面有两个核心的线程,一个是用来调度的线程,会一直扫表,看表中哪些任务该执行了;还有一个是时间轮线程,主要是向触发器线程池提交触发任务的。
    ptaooo
        3
    ptaooo  
       161 天前
    按照之前的经验来说,xxl-job 应该是可以满足需求的。
    我的理解是你这里的后端一共需要三个服务,①业务后端,②xxl-job 管理端,③任务执行器,大致如下。
    1. 部署好服务,在 [xxl-job 管理端] 配置好你的任务执行器,参考 xxl-job 的文档,用 Bean 运行模型就可以
    2. 用户通过 [业务后端] 创建任务,后端创建任务的逻辑中调用 [xxl-job 管理端] 创建对应的任务,并启动任务,返回任务 id 记录到 [业务后端] 中
    3. [xxl-job 管理端] 会根据任务的调度配置去触发 [任务执行器] 执行具体的业务。
    用 xxl-job 的好处就是你只需要实现你的业务逻辑,关于定时任务的管理和调度他都做好了。
    moell
        4
    moell  
    OP
       161 天前
    @burymme11 主要还是每次去拉取数据库比较耗资源,这里的规则会非常多,加上可能需要更小单位定时任务。
    moell
        5
    moell  
    OP
       161 天前
    @dlmy @ptaooo 非常感谢,那我研究研究 xxl-job
    Linoisy
        6
    Linoisy  
       161 天前
    PowerJob
    masterclock
        8
    masterclock  
       161 天前
    temporal 的 schedule ,好像很适合
    yingxiangyu
        9
    yingxiangyu  
       161 天前
    apscheduler
    moell
        10
    moell  
    OP
       161 天前
    @Linoisy 这个也不错,我看看文档,谢谢
    @kingofzihua robfig/cron 之前也用过,但是感觉普通的 cron 这种,满足不了我的需求,谢谢
    @masterclock 谢谢,我了解了解。
    burymme11
        11
    burymme11  
       161 天前   ❤️ 2
    @moell 抱歉,刚才没细看。“用户自主创建定时任务”,竟然允许用户创建自定义的定时任务?? 10W 个用户就完全可以出现 10W 个自定义的定时任务?看你们现在的用户量了,xxl-job 似乎有点不合适了。
    建议考虑下 RocketMQ 的延时任务,不断的消费再重投递,实现定时轮询的功能。Apache 开源的 4.8 以上,好像支持 14 小时内的任意延时了(如果有预算的话,直接买阿里云的 MQ 吧,延迟支持更全面)
    burymme11
        12
    burymme11  
       161 天前
    @burymme11 是 24 小时
    moell
        13
    moell  
    OP
       161 天前
    @burymme11 我们是用于物联网,他会有智能场景,设置定时任务。终端设备没有计算能力的话, 会依赖于服务端发送指令。
    moell
        14
    moell  
    OP
       161 天前
    @ptaooo 关于第二步,“后端创建任务的逻辑中调用 [xxl-job 管理端] 创建对应的任务”,xxl-job 我怎么看没有接口调用添加的,必须手动添加,是这样吗?
    burymme11
        15
    burymme11  
       161 天前
    @moell 用 xxl-job 没遇到过类似你这样的场景。看需要服务端支持的设备数量了,xxl-job 的话,小几千应该可以搞定,上 W 我不清楚了,你可以试试。
    burymme11
        16
    burymme11  
       161 天前
    @moell 支持 http 的添加的,你在 admin 页面可以拿到各个接口的 curl 的。干脆你直接读写 admin 的数据库吧,这样最方便。
    SilentRhythm
        17
    SilentRhythm  
       161 天前
    @moell #14
    其实看看 xxl-admin 的登录逻辑,做个爬虫也很简单的
    LoveyLoverson
        18
    LoveyLoverson  
       161 天前
    使用 MQ 的延迟消息是否可行
    ShuWei
        19
    ShuWei  
       161 天前
    @moell 你说的这个场景,小米就是这么做的,但是问题真的很多很多,你这个应该主要还是服务端多投入硬件资源了,市面上大部份解决方案应该都是可以满足的,我之前做过类似的场景,如果不想延时太大,就增加服务端硬件投入,增大服务端的并发能力,尽可能保证任务执行不会被耽误就好了不过你的任务应该都是比较恒定的,服务端只是生成指令下发,没有最终的任务执行,应该是比较好根据任务并发量来评估
    ysjiang4869
        20
    ysjiang4869  
       161 天前 via Android   ❤️ 1
    最近遇到和你一样的场景,纠结调研了比较久。想法是:多个后端业务,负责管理用户不同业务下的定时,定时创建到定时服务,包括业务回调地址。定时服务管理 corn ,触发后直接 call 回调地址给业务后端处理。
    定时服务本身自己设计一个通用接口,后面的实现可以根据用户量阶段调整。目前了解了几个方案:1 是自己实现时间轮,根据时间轮大小定期轮询数据库,可以结合其他来源 job 处理分布式分片; 2 是 quartz ,小数据量性能还行,可以前期快速搭建业务; 3 是 elastic-job ,可以手动添加,背后基于 quartz 做的。4 是 xxl-job ,xxl-job 不能动态创建复杂的,新版本定时是时间轮实现,但是 xxl 可以动态创建 http 类型的 job ,可以把 cron 服务 http 回调放在 xxl 里面
    ysjiang4869
        21
    ysjiang4869  
       161 天前 via Android
    之前看小米还是美团的一个实现,就是利用 mq 延迟队列做
    moell
        22
    moell  
    OP
       161 天前
    @ShuWei 是的,如果我自己实现时间轮,我的想法是,我当前卡槽的数据投递到队列,让队列进行消费,如果需要足够快,就需要增加消费能力。能说说大概会遇到的问题吗?
    moell
        23
    moell  
    OP
       161 天前
    @ysjiang4869 https://segmentfault.com/a/1190000022783535 看过这方案吗? 朋友他们公司的思路非常完整了。就是没有开源。
    关于 1, 我现在的理解,是不是不应该去轮训数据,启动服务的时候,直接维护这个卡槽的队列,可以维护在 redis 中,然后,到了时间时,直接新开启一个线程/协程去投递队列,然后消费的服务进行消费。

    你们这边确定方案了吗? 可以多交流交流
    moell
        24
    moell  
    OP
       161 天前
    @LoveyLoverson 延时队列我感觉也可行,我找找看他们说的小米美团的方案。
    moell
        25
    moell  
    OP
       161 天前
    @burymme11 @SilentRhythm 多谢解惑
    ShuWei
        26
    ShuWei  
       161 天前   ❤️ 1
    @moell 这个过程,可能产品设计上要注意,比如说时间粒度不能太细,最终任务的逻辑不能过于复杂,尽量不要出现相互依赖的任务等等,这些都会带来服务端或者设备端的各种问题,建议你们先做,遇到问题了再做一些修正就是了
    moell
        27
    moell  
    OP
       161 天前
    @ShuWei 好的。谢谢
    SmiteChow
        28
    SmiteChow  
       161 天前
    生成任务和消费任务是两码事,不要混为一谈
    kuituosi
        29
    kuituosi  
       161 天前   ❤️ 1
    1.异步队列基本不存在时效性问题,有的话是你使用不当造成的
    2.每秒都重复执行任务不适合大规模任务系统,需要采用其他方式
    3.时间轮太多任务导致效率低的话可以考虑层级时间轮
    4. xxl-job 本质是一个伪分布式,实质是单机的任务工具,对你的需求没有任何帮助
    Mystery0
        30
    Mystery0  
       161 天前 via Android
    我这里也有这种场景,用户可以设置一段时间内的定时任务,量也不大,就用 go 的 channel 来做定时,每隔一段时间往 channel 发一个消息,调度器去数据库拉取这段时间需要执行的任务,然后交给 worker 执行
    因为我这里量不大而且对时间不用太敏感(允许有 1-2 分钟的偏差),所以就自己写了一个简单的

    https://github.com/Mystery00/go-job
    moell
        31
    moell  
    OP
       160 天前
    @kuituosi 谢谢,很受用
    @Mystery0 谢谢,我参考参考。1-2 分钟对于我们来说可能有点接受不了。你现在时间偏差是因为消费不够及时的原因吗?
    Mystery0
        32
    Mystery0  
       160 天前 via Android
    @moell 不是,因为额外有一个定时任务去数据库拉任务,整体执行的误差就在这里,我的场景对时间不敏感,就简单写了

    现在想来,我的更重要的应该是用 channel 和数据库来支持多执行器了,任务执行那里似乎没啥高级的😂😂
    ptaooo
        33
    ptaooo  
       157 天前   ❤️ 1
    @moell
    刚才翻了一下代码,我这边应该是和 xxl-job 管理界面用的相同的 api ,从界面操作上看相关的是哪个接口,/dog
    moell
        34
    moell  
    OP
       157 天前
    @ptaooo 谢谢,有心了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2754 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 08:55 · PVG 16:55 · LAX 00:55 · JFK 03:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.