考虑延时和定时消息,是因为遇到了一个业务场景:
前置任务完成时发送消息,但因为一些业务原因,不希望消息马上被消费,因此需要设置延时。
几种解决思路
考虑了几种实现方式:
- 消息队列的延迟消息,目前仅有RocketeMQ等少量产品支持。
- Java异步线程
- 持久化定时任务
因为目前业务量不大、尽可能实现简单、快速,最终选择了方案一,理由如下:
- 异步线程虽然实现简单,但有消息未发送风险,如线程等待期间、进程突然crash。而ONS不依赖java进程、无该问题,后面会讲到。
- 持久化定时任务可以解决消息丢失、任务争抢等问题,但要实现可靠方案,复杂度比较高、要花费很多时间。
- 消息队列虽然也可能出现生产丢信的风险,但已经做了一定的保证,相比异步线程风险更低,可以接受。
以后业务量大或要求高了,再改成方案三,或者方案一结合方案三:
- 性能相对有保障;而消息队列延时消息可能出现存储和消费性能问题
- 消息/任务吞吐量,可以通过增加节点快速扩容
- 存储上可以单独规划、快速扩容
- 不用担心消息堆积时、宕机后运行时态会丢失
简单介绍下几种方案的实现。
实现方案
ONS延迟消息
据官方说法,ONS是基于RocketMQ实现的产品,但和开源RocketMQ的api上有一些不同。
RocketMQ
RocketMQ
的消息(org.apache.rocketmq.common.message.Message
),通过指定延迟级别来设置延时:
...
// 10秒后传递给consumer
message.setDelayTimeLevel(3);
...
该方式仅支持特定的level
,如1s/5s/1