wuzhizuiguo
V2EX  ›  Java

时光树洞的按时间发送顺序是怎么做的 ,rabbitmq 的"后入先出"

  •  
  •   wuzhizuiguo · Dec 5, 2019 · 4813 views
    This topic created in 2364 days ago, the information mentioned may be changed or developed.
    看到有时光树洞, 选择一个时间点发送定时的邮件, 这种是保存到数据库,然后定时(每秒)查询数据库获取当时的邮件,然后发送?
    还是在用户提交后,写入数据库,写入消息队列,设置过期时间 (延时队列),最后根据时间先后顺序发送(但是队列是先入先出的)
    请问下大佬,这种是怎么做的?
    17 replies    2019-12-08 17:28:06 +08:00
    skypyb
        1
    skypyb  
       Dec 5, 2019
    可以用时间轮
    rabbitmq 消息 TTL+死信也可以啊。
    wuzhizuiguo
        2
    wuzhizuiguo  
    OP
       Dec 5, 2019
    @skypyb 谢谢. rabbitmq 消息 TTL+死信队列 ,请问一下, 怎么实现 A 消息 10 秒过期, B 消息 5 秒过期, A 先进入队列, B 再进入, B 先出来发送邮件 . 博客上上说 , 队列进入时按照先入先出, 如果 B 过期了 还得等 A 过期了才会进入消费队列.
    skypyb
        3
    skypyb  
       Dec 5, 2019
    @wuzhizuiguo rabbitmq 可以设置每条消息的过期时间。不过不叫 ttl,具体参数叫啥搜索引擎搜一下吧
    wuzhizuiguo
        4
    wuzhizuiguo  
    OP
       Dec 5, 2019
    @skypyb 好的,谢谢. 是这个参数 message.getMessageProperties().setExpiration, 设置每条消息的过期时间. 现在如果每条消息设置同样的过期时间,A,B,C...都是 10 秒, 或者过期时间依次递增 10 秒,11 秒... 已经实现了. 会按过期时间顺序从死信队列里,然后进入 exchange 绑定的消费队列. 但是如果邮件发送时间 有 2 天后,1 天后,3 天后 这种 1 天后就得等 2 天后这条过期了,才会轮到它..
    FaceBug
        5
    FaceBug  
       Dec 5, 2019
    如果没有当天入洞,当天就要取出来的场景话,建议每天把次日的查出来,写到发送队列。

    不同 mq 有不同的机制,如果 MQ 本身没有排序功能,可以用 redis 的 zset 先按秒排序,然后入队列,甚至直接用 redis 的 zset,每秒提取已经到期的消息发送。
    wuzhizuiguo
        6
    wuzhizuiguo  
    OP
       Dec 5, 2019
    @cepczkd 谢谢. 如果没有当天写,当天就要发送的场景: 今天取出昨天的,查询排序,设置每条过期时间,写入延迟队列,发送,这个可行. 不过当天写 当天发送还是要有的..
    redis zet 这个是有新提交的,就重新写入,然后根据 score 值排序, 获取需要发送的消息. 这个可以
    mango88
        7
    mango88  
       Dec 5, 2019
    @wuzhizuiguo
    RabbitMQ 有个插件 rabbitmq_delayed_message_exchange,
    可以实现任意延时消息,而不同等待前面的消息过期,后面的消息才会过期这种情况
    mango88
        8
    mango88  
       Dec 5, 2019
    @mango88 不同 => 不用
    wuzhizuiguo
        9
    wuzhizuiguo  
    OP
       Dec 5, 2019
    @mango88 谢谢. 这个好.如果安装了 就可以通过设置过期时间来实现了. (就是要安装插件..)
    wuzhizuiguo
        10
    wuzhizuiguo  
    OP
       Dec 5, 2019
    暂时准备用把数据放到 zset 和 mysql 里, spring boot 里 跑一个间隔 1 秒的定时器, 根据 score 值排序 把等于或小于当前时间的数据取出来发送,(再删除这些发送过的)
    zhady009
        11
    zhady009  
       Dec 5, 2019
    redisson 有这种实现..还挺简单的 RScheduledExecutorService

    不过还是得用 mysql 记录一下 taskId
    wuzhizuiguo
        12
    wuzhizuiguo  
    OP
       Dec 6, 2019
    star7th
        13
    star7th  
       Dec 6, 2019
    两种方式都能做。用哪种方式都很轻松。第一种是起一个 cron 任务即可。用队列来做的话,利用我另一个开源项目 github.com/star7th/htq 里的定时任务特性就能做到。
    wuzhizuiguo
        15
    wuzhizuiguo  
    OP
       Dec 8, 2019
    @zhady009 好的,谢谢.我先用普通的定时器做做看,成功了再学下这个 redisson
    wuzhizuiguo
        16
    wuzhizuiguo  
    OP
       Dec 8, 2019
    @star7th 好的,谢谢,就是看到了答主的时光树洞.
    wuzhizuiguo
        17
    wuzhizuiguo  
    OP
       Dec 8, 2019
    已经确认可以按照过期时间发送邮件. 用的是普通前端提交参数(假设,我不会前端, 用的 postman),后台 mysql 储存信息, 同时写入 redis 的 hash 表和 zset 中,设置 score 值为过期时间.接着 spring boot 启动一个定时器,@Scheduled, 设置为上一次结束到到上一次任务开始为 1 秒间隔. 在其中读取 zset 中 0~当前时间的元素(邮件 id), 再去 hash 中找到对应邮件 id 的邮件具体信息,然后删除对应的记录, 接着直接写入消息队列,然后从消息队列里出来, RPC 调用邮件发送接口, 这个地方如果量大了,可以用线程池来 RPC 调用,因为之前其他地方出现过 Hystrix 默认的线程数错误问题.
    感谢各位大佬的热心解答,谢谢.
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1413 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 17:02 · PVG 01:02 · LAX 10:02 · JFK 13:02
    ♥ Do have faith in what you're doing.