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

2019-12-05 10:47:28 +08:00
 wuzhizuiguo
看到有时光树洞, 选择一个时间点发送定时的邮件, 这种是保存到数据库,然后定时(每秒)查询数据库获取当时的邮件,然后发送?
还是在用户提交后,写入数据库,写入消息队列,设置过期时间 (延时队列),最后根据时间先后顺序发送(但是队列是先入先出的)
请问下大佬,这种是怎么做的?
4016 次点击
所在节点    Java
17 条回复
skypyb
2019-12-05 11:01:55 +08:00
可以用时间轮
rabbitmq 消息 TTL+死信也可以啊。
wuzhizuiguo
2019-12-05 11:10:10 +08:00
@skypyb 谢谢. rabbitmq 消息 TTL+死信队列 ,请问一下, 怎么实现 A 消息 10 秒过期, B 消息 5 秒过期, A 先进入队列, B 再进入, B 先出来发送邮件 . 博客上上说 , 队列进入时按照先入先出, 如果 B 过期了 还得等 A 过期了才会进入消费队列.
skypyb
2019-12-05 11:13:54 +08:00
@wuzhizuiguo rabbitmq 可以设置每条消息的过期时间。不过不叫 ttl,具体参数叫啥搜索引擎搜一下吧
wuzhizuiguo
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
2019-12-05 11:33:23 +08:00
如果没有当天入洞,当天就要取出来的场景话,建议每天把次日的查出来,写到发送队列。

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

不过还是得用 mysql 记录一下 taskId
wuzhizuiguo
2019-12-06 10:28:15 +08:00
star7th
2019-12-06 11:18:38 +08:00
两种方式都能做。用哪种方式都很轻松。第一种是起一个 cron 任务即可。用队列来做的话,利用我另一个开源项目 github.com/star7th/htq 里的定时任务特性就能做到。
zhady009
2019-12-06 12:17:13 +08:00
wuzhizuiguo
2019-12-08 14:52:47 +08:00
@zhady009 好的,谢谢.我先用普通的定时器做做看,成功了再学下这个 redisson
wuzhizuiguo
2019-12-08 14:54:31 +08:00
@star7th 好的,谢谢,就是看到了答主的时光树洞.
wuzhizuiguo
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 默认的线程数错误问题.
感谢各位大佬的热心解答,谢谢.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/626130

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX