小结:
1、Exactly-Once 是指发送到消息系统的消息只能被消费端处理且仅处理一次,即使生产端重试消息发送导致某消息重复投递,该消息也在消费端也只被消费一次。
- 消息队列 RocketMQ >
- 开发指南 >
- SDK 参考(TCP 版) >
- Java SDK >
- Exactly-Once 投递语义
Exactly-Once 投递语义
Exactly-Once 投递语义_Java SDK_SDK 参考(TCP 版)_开发指南_消息队列 RocketMQ-阿里云 https://help.aliyun.com/document_detail/102777.html
概念介绍
Exactly-Once 是指发送到消息系统的消息只能被消费端处理且仅处理一次,即使生产端重试消息发送导致某消息重复投递,该消息也在消费端也只被消费一次。Exactly-Once 语义是消息系统和流式计算系统中消息流转的最理想状态,但是在业界并没有太多理想的实现,因为真正意义上的 Exactly-Once 依赖消息系统的服务端、消息系统的客户端和用户消费逻辑这三者状态的协调,例如,当您的消费端完成一条消息的消费处理后出现异常宕机,而消费端重启后由于消费的位点没有同步到消息系统的服务端,该消息又可能被重复消费。
业界对于 Exactly-Once 投递语义存在很大的争议,很多人会拿出“FLP不可能理论”或者其他一致性定律对此议题进行否定,但事实上,特定场景的 Exactly-Once 语义实现并不是非常复杂,只是因为通常大家没有精确的描述问题的本质。当你的问题是一条消息的消费结果只能在业务系统中生效一次,你需要解决的只是如何保证同一条消息的消费幂等问题,消息队列 RocketMQ 的 Exactly-Once 语义就是解决业务中最常见的一条消息的消费结果(消息在消费端计算处理的结果)在数据库系统中有且仅生效一次的问题。
典型使用场景
在电商系统中,上游实时计算模块发布商品价格变更的信息,异步通知到下游商品管理模块进行价格变更。此时,需要保证每一条信息的消费幂等,即重复的价格变更信息只会生效一次,这样便不会发生价格多次重复修改的情况,确保实现了消息消费的幂等。
使用方法
消息队列 RocketMQ 的 Exactly-Once 投递语义适用于“接收消息 -> 处理消息 -> 结果持久化到数据库”的流程,能够保证您的每一条消息消费的最终处理结果写入到您的数据库一次且仅一次,保证消息消费的幂等。若要使用该语义,请按照以下步骤进行操作:
-
在应用中添加 SDK 包依赖和 Spring 3.0 以上版本的依赖。详情请见步骤一:添加依赖。
-
在用于存储消息消费结果的数据库中创建 transaction_record 表。详情请见步骤二:创建消费事务表。
注意:存储消息消费结果的数据库系统必须支持本地事务。
-
在消息生产端使用 PropertyKeyConst.EXACTLYONCE_DELIVERY 属性设置打开 Exactly Once 投递语义。详情请见步骤三:生产端开启 Exactly-Once 投递语义。
-
在消息消费端创建 ExactlyOnceConsumer,并开启 Exactly-Once 的消费模式。详情请见步骤四:消费端开启 Exactly-Once 投递语义。