githubEdit

2. 使用方式

2.1 生产

通过deliverAt方法指定一个绝对时间戳,通过deliverAfter指定一个相对时间,如下示例代码:

Producer<String> producer = client.newProducer(Schema.STRING)
        .topic("public/default/delayed-test").create();

// message to be delivered at the configured delay interval
producer.newMessage().deliverAfter(10, TimeUnit.SECONDS).value(sdf.format(new Date())).send();

// message to be delivered at the configure time
producer.newMessage().deliverAt(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10)).send();

2.2 消费

延迟消息的消费者只能使用shared、key-shared订阅类型,如果消费端使用exclusive、failover订阅模式,那么broker还是会立刻分发延迟消息,无视延迟时间,这一点一定要注意。

读者可能会疑惑为什么exclusive、failover订阅模式不支持延迟消息,也许是因为这两种订阅模式能保证消息顺序,而延迟消息会破坏这种顺序,另一方面,改造这块代码也是比较难的一个事情。具体讨论可参见:

2.3 消息顺序

使用延迟消息时注定是无法保证严格顺序的,如下图:

2.4 时间精度与长度

精度

默认精度为1s。

配置delayedDeliveryTickTimeMillis影响了延迟消息的精度,延迟队列模块的定时任务是每1s检查一下消息是否到期,因此默认精度是1s。

虽然用户可以将这个配置改成1ms,但是仍然无法保证消息的投递时间跟指定延迟时间的误差在1ms的精度内,毕竟Pulsar全链路P99延迟也才达到几ms的级别,还有topic unload等特殊情况会导致消息重建的耗时。

如果对延迟精度有高要求的话,可以考虑消费端自己实现内存轮询方案,比如说用户需要消息延迟1d,但是精度达到10ms,那么可以使用Pulsar延迟队列,指定消息延迟23h59min59s,那么消息能保证在1s前达到消费端,通过短暂的轮询机制即可实现高精度的延迟消息了。

长度

理论上对延迟时间长度没限制,如7天、一个月甚至一年。但是由于Pulsar还有TTL等机制,如果延迟的时间超过消息保存时间,那么必定会被清理掉,到达延迟时间后也无法读取到消息来分发给消费者,因此用户一定要保证延迟时间小于保存时间,否则消息会丢失。

还有一些常见问题:

  • 定时消息在定时时间到达前可以撤回或修改定时时间吗?

不支持。

  • 定时时间设置一个已过去的时间会怎么样?

消息会被立即投递。

Last updated

Was this helpful?