Exactly-Once 投递语义

本文主要介绍消息队列 RocketMQ 的 Exactly-Once 投递语义的概念和典型使用场景,以便您理解如何使得消息只被消费端处理且仅处理一次。

关于如何使用 Exactly-Once 投递语义,请参见使用 Exactly-Once 投递语义收发消息。

什么是 Exactly-Once 投递语义

Exactly-Once 是指发送到消息系统的消息只能被消费端处理且仅处理一次, 即使生产端重试消息发送导致某消息重复投递,该消息在消费端也只被消费一次。

Exactly-Once 语义是消息系统和流式计算系统中消息流转的最理想状态, 但是在业界并没有太多理想的实现,因为真正意义上的 Exactly-Once 依赖消息系统的服务端、消息系统的客户端和用户消费逻辑这三者状态的协调, 例如,当您的消费端完成一条消息的消费处理后出现异常宕机,而消费端重启后由于消费的位点没有同步到消息系统的服务端,该消息有可能被重复消费。

业界对于 Exactly-Once 投递语义存在很大的争议,很多人会拿出 “FLP 不可能理论”或者其他一致性定律对此议题进行否定, 但事实上,特定场景的 Exactly-Once 语义实现并不是非常复杂,只是因为通常大家没有精确的描述问题的本质。

如果您需要解决的问题是一条消息的消费结果只能在业务系统中生效一次,你需要解决的只是如何保证同一条消息的消费幂等问题, 消息队列 RocketMQ 的 Exactly-Once 语义就是解决业务中最常见的一条消息的消费结果(消息在消费端计算处理的结果)在数据库系统中有且仅生效一次的问题。

典型使用场景

在电商系统中,上游实时计算模块发布商品价格变更的信息,异步通知到下游商品管理模块进行价格变更。 此时,需要保证每一条信息的消费幂等,即重复的价格变更信息只会生效一次,这样便不会发生价格多次重复修改的情况,确保实现了消息消费的幂等。

商品价格变更场景