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

延迟队列落地方案

  •  
  •   awanganddong · 2020-10-16 10:07:17 +08:00 · 3142 次点击
    这是一个创建于 1500 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求是这样的,后台配置时间,然后给用户发消息。 在用户关注后,根据这个时间发消息 比如 5s,发送一条数据 10s,发送一条数据。

    现在用的定时任务处理,这样大概会有 1 分钟左右误差。

    如果将定时任务设置成秒级,则 1s 中处理不完业务。


    如果用延迟队列。 用户关注,然后扫配置表,把用户 ID+延迟时间写入 redis zset 。然后一直消费这个有序队列。 这样存在一个问题,如果管理员修改后台配置信息,我就需要批量修改 zset 里边的时间。

    也就是需要修改整个公众号所有的 zset 数据。

    有什么简单一些的方案吗

    17 条回复    2020-10-16 14:00:28 +08:00
    coderxy
        1
    coderxy  
       2020-10-16 10:15:06 +08:00
    可以考虑配置修改只对修改后生效,前面的不管
    BBCCBB
        2
    BBCCBB  
       2020-10-16 10:15:26 +08:00
    1. redisson (用下来偶尔会有丢失的情况出现, 需要一个兜底的方案)
    2. pulsar mq 或者其他支持延迟队列的 mq.
    3. 扫表(缺点你说了).
    chogath
        3
    chogath  
       2020-10-16 10:17:15 +08:00
    redis bull - node.js
    specita
        4
    specita  
       2020-10-16 10:19:11 +08:00
    秒级扫表把需要处理的用户放入队列里串行处理
    awanganddong
        5
    awanganddong  
    OP
       2020-10-16 10:27:13 +08:00
    后台数据库如下,

    一张表存储是否开启

    公众号 是否开启是否发送信息

    还有一张子表

    记录 延迟时间 发送内容

    ------------------------------------------

    用延迟队列现在考虑的问题就是我写入 zset 数据 ,但是后台修改配置的问题。

    秒级扫表,我是以配置表为主表 。然后获取可用公众号配置项,然后循环用户表,比对用户表与配置表的差值。

    担心的问题就是在对用户表比对的过程。如果不能快速响应,那就比对失败。 因为精度是秒级别的
    Veneris
        6
    Veneris  
       2020-10-16 10:33:10 +08:00
    MQ 支持延时消费的
    axbx
        7
    axbx  
       2020-10-16 10:35:57 +08:00
    MQ 有的功能不要再折腾,大概率是比自己写的好用
    wxy1991
        8
    wxy1991  
       2020-10-16 10:43:32 +08:00
    设置一个时间的浮动值,比如第一次配置当作基准时间,比较的时候比较 基准时间+浮动时间<=>zset 的时间,修改配置时,其实是修改了浮动时间,这样就可以随意修改配置,代码改动也最小
    lidlesseye11
        9
    lidlesseye11  
       2020-10-16 10:55:31 +08:00
    Thread.sleep(5000)
    DavidNineRoc
        10
    DavidNineRoc  
       2020-10-16 11:09:38 +08:00
    来个简单一点的处理.
    发送的间隔时间 interval == 5s || 10s
    用户创建时间点 created_at
    发送延迟时间点 delay_at

    // 当用户关注之后, 往 zset 存储
    ZADD xxx delay_at "id, interval=5, created_at, "

    // 当管理员改为 20s 后, 找到最近 20s 内创建的所有用户, 重新往延时队列加
    ZADD xxx delay_at "id, interval=20, created_at, "

    // 延时队列消费的进程加一个判断.
    if interval not in 管理员的配置列表
    return false;
    lzxz1234
        11
    lzxz1234  
       2020-10-16 11:15:08 +08:00
    扫表也不一定必须有误差,每分钟扫表将要执行的放到内存队列里,到时间执行就可以了

    混合方案,也不需要额外依赖 redis 队列啥的
    sujin190
        12
    sujin190  
       2020-10-16 11:15:51 +08:00
    https://github.com/snower/forsun

    之前做的一个定时服务,通过 key 指定定时任务,通过 key 随时可以修改,每个任务秒级定时,后端持久化用 redis 不担心丢失,已经稳定用在日百万级订单超时这样的任务处理,可以看看能不能满足
    Evilk
        13
    Evilk  
       2020-10-16 11:18:49 +08:00
    RabbitMQ,本身就支持死信队列(延时队列)
    awanganddong
        14
    awanganddong  
    OP
       2020-10-16 11:23:03 +08:00
    工期紧。只能简单粗暴了
    @DavidNineRoc 这个方案可以。唯一瓶颈就是 在 zset 修改文件这里了
    mosliu
        15
    mosliu  
       2020-10-16 11:25:48 +08:00
    一个线程 定时任务,取出要发送的任务,
    另外起线程做发送不就行了。
    awanganddong
        16
    awanganddong  
    OP
       2020-10-16 12:07:01 +08:00
    理清楚了,

    最开始我困惑的点,在于后台修改配置文件,那怎么修改延迟队列的数据内容。

    刚明白过来,

    配置表修改内容后,我只需要关注添加就可以了。

    消费的时候,我验证下无效的消费就可以了。
    857681664
        17
    857681664  
       2020-10-16 14:00:28 +08:00
    rabbitMQ 的延时队列也可以处理。
    用户关注之后把 userId 放入队列,同时设置延时时间,在消费完只需要再查一次配置表,把新的延时时间设置到消息上,再把消息塞回队列即可。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2986 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:22 · PVG 21:22 · LAX 05:22 · JFK 08:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.