时光树洞的按时间发送顺序是怎么做的 ,rabbitmq 的"后入先出" - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wuzhizuiguo
V2EX    Java

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

  •  
  •   wuzhizuiguo 2019-12-05 10:47:28 +08:00 4425 次点击
    这是一个创建于 2149 天前的主题,其中的信息可能已经有所发展或是发生改变。
    看到有时光树洞, 选择一个时间点发送定时的邮件, 这种是保存到数据库,然后定时(每秒)查询数据库获取当时的邮件,然后发送?
    还是在用户提交后,写入数据库,写入消息队列,设置过期时间 (延时队列),最后根据时间先后顺序发送(但是队列是先入先出的)
    请问下大佬,这种是怎么做的?
    17 条回复    2019-12-08 17:28:06 +08:00
    skypyb
        1
    skypyb  
       2019-12-05 11:01:55 +08:00
    可以用时间轮
    rabbitmq 消息 TTL+死信也可以啊。
    wuzhizuiguo
        2
    wuzhizuiguo  
    OP
       2019-12-05 11:10:10 +08:00
    @skypyb 谢谢. rabbitmq 消息 TTL+死信队列 ,请问一下, 怎么实现 A 消息 10 秒过期, B 消息 5 秒过期, A 先进入队列, B 再进入, B 先出来发送邮件 . 博客上上说 , 队列进入时按照先入先出, 如果 B 过期了 还得等 A 过期了才会进入消费队列.
    skypyb
        3
    skypyb  
       2019-12-05 11:13:54 +08:00
    @wuzhizuiguo rabbitmq 可以设置每条消息的过期时间。不过不叫 ttl,具体参数叫啥搜索引擎搜一下吧
    wuzhizuiguo
        4
    wuzhizuiguo  
    OP
       2019-12-05 11:22:22 +08:00
    @skypyb 好的,谢谢. 是这个参数 message.getMessageProperties().setExpiration, 设置每条消息的过期时间. 现在如果每条消息设置同样的过期时间,A,B,C...都是 10 秒, 或者过期时间依次递增 10 秒,11 秒... 已经实现了. 会按过期时间顺序从死信队列里,然后进入 exchange 绑定的消费队列. 但是如果邮件发送时间 有 2 天后,1 天后,3 天后 这种 1 天后就得等 2 天后这条过期了,才会轮到它..
    FaceBug
        5
    FaceBug  
       2019-12-05 11:33:23 +08:00
    如果没有当天入洞,当天就要取出来的场景话,建议每天把次日的查出来,写到发送队列。

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

    不过还是得用 mysql 记录一下 taskId
    wuzhizuiguo
        12
    wuzhizuiguo  
    OP
       2019-12-06 10:28:15 +08:00
    star7th
        13
    star7th  
       2019-12-06 11:18:38 +08:00
    两种方式都能做。用哪种方式都很轻松。第一种是起一个 cron 任务即可。用队列来做的话,利用我另一个开源项目 github.com/star7th/htq 里的定时任务特性就能做到。
    wuzhizuiguo
        15
    wuzhizuiguo  
    OP
       2019-12-08 14:52:47 +08:00
    @zhady009 好的,谢谢.我先用普通的定时器做做看,成功了再学下这个 redisson
    wuzhizuiguo
        16
    wuzhizuiguo  
    OP
       2019-12-08 14:54:31 +08:00
    @star7th 好的,谢谢,就是看到了答主的时光树洞.
    wuzhizuiguo
        17
    wuzhizuiguo  
    OP
       2019-12-08 17:28:06 +08:00
    已经确认可以按照过期时间发送邮件. 用的是普通前端提交参数(假设,我不会前端, 用的 postman),后台 mysql 储存信息, 同时写入 redis 的 hash 表和 zset 中,设置 score 值为过期时间.接着 spring boot 启动一个定时器,@Scheduled, 设置为上一次结束到到上一次任务开始为 1 秒间隔. 在其中读取 zset 中 0~当前时间的元素(邮件 id), 再去 hash 中找到对应邮件 id 的邮件具体信息,然后删除对应的记录, 接着直接写入消息队列,然后从消息队列里出来, RPC 调用邮件发送接口, 这个地方如果量大了,可以用线程池来 RPC 调用,因为之前其他地方出现过 Hystrix 默认的线程数错误问题.
    感谢各位大佬的热心解答,谢谢.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2181 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 16:03 PVG 00:03 LAX 09:03 JFK 12:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86