You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by du...@apache.org on 2022/09/03 09:42:00 UTC

[rocketmq-site] branch new-official-website updated: Rocketmq website message hotfix (#195)

This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch new-official-website
in repository https://gitbox.apache.org/repos/asf/rocketmq-site.git


The following commit(s) were added to refs/heads/new-official-website by this push:
     new 45ea5213 Rocketmq website message hotfix (#195)
45ea5213 is described below

commit 45ea5213b3b92ecdd30ae15c186490b6c52abc8f
Author: Jodie Yang <ma...@alibaba-inc.com>
AuthorDate: Sat Sep 3 17:41:55 2022 +0800

    Rocketmq website message hotfix (#195)
    
    * [ISSUE apache#193] add description for transaction check and preserving properties
    
    * add description for message type and produce doc
---
 "docs/01-\344\273\213\347\273\215/03whatis.md"      |  11 ++++++-----
 .../04concept1.md"                                  |  11 +++++++++--
 .../05message1.md"                                  |  11 +++++++++--
 .../06message2.md"                                  |  15 ++++++++++++++-
 .../07message3.md"                                  |  11 +++++++++++
 .../09message5.md"                                  |  20 +++++++++++++++++---
 ...201\257\347\244\272\344\276\213\344\270\200.png" | Bin 0 -> 134035 bytes
 ...212\241\347\244\272\344\276\213\344\272\214.png" | Bin 0 -> 190210 bytes
 ...201\257\347\244\272\344\276\213\344\270\200.png" | Bin 0 -> 121608 bytes
 ...201\257\347\244\272\344\276\213\344\270\200.png" | Bin 0 -> 191635 bytes
 10 files changed, 66 insertions(+), 13 deletions(-)

diff --git "a/docs/01-\344\273\213\347\273\215/03whatis.md" "b/docs/01-\344\273\213\347\273\215/03whatis.md"
index 8a142394..1ea9b380 100644
--- "a/docs/01-\344\273\213\347\273\215/03whatis.md"
+++ "b/docs/01-\344\273\213\347\273\215/03whatis.md"
@@ -69,14 +69,15 @@ import TabItem from '@theme/TabItem';
 
 :::
 
-- 为了**水平扩展**,RocketMQ 对 Topic进行了分区,这种操作被称为**队列**(MessageQueue)。
+- 为了消息写入能力的**水平扩展**,RocketMQ 对 Topic进行了分区,这种操作被称为**队列**(MessageQueue)。
 
-- 为了**并发消费**,Consumer Group的概念应运而生。
+- 为了消费能力的**水平扩展**,ConsumerGroup的概念应运而生。
 
 :::info
 
-- Consumer主要有两种消费方式,即**广播模式**,和**集群模式**(图中是最常用的集群模式)。
-- 同一个 Consumer Group 中的 Consumer 实例是负载均衡消费,如图中 ConsumerGroupA 订阅 TopicA,TopicA 对应 3个队列,则 GroupA 中的 Consumer1 消费的是 MessageQueue 0和 MessageQueue 1的消息,Consumer2是消费的是MessageQueue2的消息。
+- 相同的ConsumerGroup下的消费者主要有两种负载均衡模式,即**广播模式**,和**集群模式**(图中是最常用的集群模式)。
+- 在集群模式下,同一个 ConsumerGroup 中的 Consumer 实例是负载均衡消费,如图中 ConsumerGroupA 订阅 TopicA,TopicA 对应 3个队列,则 GroupA 中的 Consumer1 消费的是 MessageQueue 0和 MessageQueue 1的消息,Consumer2是消费的是MessageQueue2的消息。
+- 在广播模式下,同一个 ConsumerGroup 中的每个 Consumer 实例都处理全部的队列。需要注意的是,广播模式下因为每个 Consumer 实例都需要处理全部的消息,因此这种模式仅推荐在通知推送、配置同步类小流量场景使用。
 
 :::
 
@@ -102,7 +103,7 @@ Apache RocketMQ 部署架构上主要分为四部分:
 
 ## 名字服务器 **NameServer**
 
-NameServer是 一个简单的 Topic 路由注册中心,支持 Topic、Broker 的动态注册与发现。
+NameServer是一个简单的 Topic 路由注册中心,支持 Topic、Broker 的动态注册与发现。
 
 主要包括两个功能:
 
diff --git "a/docs/02-\347\224\237\344\272\247\350\200\205/04concept1.md" "b/docs/02-\347\224\237\344\272\247\350\200\205/04concept1.md"
index 1bb5f75c..817527cf 100644
--- "a/docs/02-\347\224\237\344\272\247\350\200\205/04concept1.md"
+++ "b/docs/02-\347\224\237\344\272\247\350\200\205/04concept1.md"
@@ -12,7 +12,7 @@ RocketMQ 消息构成非常简单,如下图所示。
 - **transactionId** 会在事务消息中使用。
 
 :::tip
-- Tag: 不管是 RocketMQ 的 Tag 过滤还是延迟消息等都会利用 Properties 消息属性的能力
+- Tag: 不管是 RocketMQ 的 Tag 过滤还是延迟消息等都会利用 Properties 消息属性机制,这些特殊信息使用了系统保留的属性Key,设置自定义属性时需要避免和系统属性Key冲突。
 
 - Keys: 服务器会根据 keys 创建哈希索引,设置后,可以在 Console 系统根据 Topic、Keys 来查询消息,由于是哈希索引,请尽可能保证 key 唯一,例如订单号,商品 Id 等。
 :::
@@ -32,7 +32,12 @@ Message 可以设置的属性值包括:
 |      Keys      | null   | 选填   | 代表这条消息的业务关键词 |
 |      Flag      | 0      | 选填   | 完全由应用来设置,RocketMQ 不做干预                                                                                                                                               |
 | DelayTimeLevel | 0      | 选填   | 消息延时级别,0 表示不延时,大于 0 会延时特定的时间才会被消费                                                                                                                     |
-| WaitStoreMsgOK | true   | 选填   | 表示消息是否在服务器落盘后才返回应答。                                                                                                                                            |
+| WaitStoreMsgOK | true   | 选填   | 表示消息是否在服务器落盘后才返回应答。|
+
+:::tip
+RocketMQ系统保留的属性Key集合有如下,需要在使用过程中避免:
+TRACE_ON、MSG_REGION、KEYS、TAGS、DELAY、RETRY_TOPIC、REAL_TOPIC、REAL_QID、TRAN_MSG、PGROUP、MIN_OFFSET、MAX_OFFSET、BUYER_ID、ORIGIN_MESSAGE_ID、TRANSFER_FLAG、CORRECTION_FLAG、MQ2_FLAG、RECONSUME_TIME、UNIQ_KEY、MAX_RECONSUME_TIMES、CONSUME_START_TIME、POP_CK、POP_CK_OFFSET、1ST_POP_TIME、TRAN_PREPARED_QUEUE_OFFSET、DUP_INFO、EXTEND_UNIQ_INFO、INSTANCE_ID、CORRELATION_ID、REPLY_TO_CLIENT、TTL、ARRIVE_TIME、PUSH_REPLY_TIME、CLUSTER、MSG_TYPE、INNER_MULTI_QUEUE_OFFSET、_BORNHOST
+:::
 
 ## Tag
 
@@ -85,3 +90,5 @@ Apache RocketMQ 每个消息可以在业务层面的设置唯一标识码 keys 
 ## 生产者
 
 生产者(Producer)就是消息的发送者,Apache RocketMQ 拥有丰富的消息类型,可以支持不用的应用场景,在不同的场景中,需要使用不同的消息进行发送。比如在电商交易中超时未支付关闭订单的场景,在订单创建时会发送一条延时消息。这条消息将会在 30 分钟以后投递给消费者,消费者收到此消息后需要判断对应的订单是否已完成支付。如支付未完成,则关闭订单。如已完成支付则忽略,此时就需要用到延迟消息;电商场景中,业务上要求同一订单的消息保持严格顺序,此时就要用到顺序消息。在日志处理场景中,可以接受的比较大的发送延迟,但对吞吐量的要求很高,希望每秒能处理百万条日志,此时可以使用批量消息。在银行扣款的场景中,要保持上游的扣款操作和下游的短信通知保持一致,此时就要使用事务消息,下一节将会介绍各种类型
 消息的发送。
+
+:::note 需要注意的是,生产环境中不同消息类型需要使用不同的主题,不要在同一个主题内使用多种消息类型,这样可以避免运维过程中的风险和错误。 :::
\ No newline at end of file
diff --git "a/docs/02-\347\224\237\344\272\247\350\200\205/05message1.md" "b/docs/02-\347\224\237\344\272\247\350\200\205/05message1.md"
index 44971a8b..84a2e3b3 100644
--- "a/docs/02-\347\224\237\344\272\247\350\200\205/05message1.md"
+++ "b/docs/02-\347\224\237\344\272\247\350\200\205/05message1.md"
@@ -2,7 +2,11 @@
 
 ## 1.向集群中创建 Topic
 
-RocketMQ集群是默认开启了 **autoCreateTopicEnable** 配置,会自动为发送的消息创建 Topic,如果 autoCreateTopicEnable 没有开启,也可以利用 RocketMQ Admin 工具创建目标 Topic 。
+发送消息前,需要确保目标主题已经被创建和初始化。可以利用 RocketMQ Admin 工具创建目标 Topic 。
+
+RocketMQ 部署安装包默认开启了 **autoCreateTopicEnable** 配置,会自动为发送的消息创建 Topic,但该特性仅推荐在初期测试时使用。
+
+**生产环境强烈建议管理所有主题的生命周期,关闭自动创建参数**,以避免生产集群出现大量无效主题,无法管理和回收,造成集群注册压力增大,影响生产集群的稳定性。
 
 ```shell
 > sh bin/mqadmin updateTopic -c DefaultCluster -t TopicTest -n 127.0.0.1:9876
@@ -47,7 +51,7 @@ Apache RocketMQ可用于以三种方式发送消息:**同步、异步和单向
 
 ### 3.1 同步发送
 
-同步发送是指消息发送方发出一条消息后,会在收到服务端同步响应之后才发下一条消息的通讯方式,可靠的同步传输被广泛应用于各种场景,如重要的通知消息、短消息通知等。
+同步发送是最常用的方式,是指消息发送方发出一条消息后,会在收到服务端同步响应之后才发下一条消息的通讯方式,可靠的同步传输被广泛应用于各种场景,如重要的通知消息、短消息通知等。
 
 
 ![同步发送](../picture/同步发送.png)
@@ -82,6 +86,9 @@ public class SyncProducer {
 }
 ```
 
+:::note
+同步发送方式请务必捕获发送异常,并做业务侧失败兜底逻辑,如果忽略异常则可能会导致消息未成功发送的情况。
+:::
 
 
 ### 3.2 异步发送
diff --git "a/docs/02-\347\224\237\344\272\247\350\200\205/06message2.md" "b/docs/02-\347\224\237\344\272\247\350\200\205/06message2.md"
index a89b26bc..00124b7a 100644
--- "a/docs/02-\347\224\237\344\272\247\350\200\205/06message2.md"
+++ "b/docs/02-\347\224\237\344\272\247\350\200\205/06message2.md"
@@ -5,9 +5,20 @@
 
 对于一个指定的Topic,消息严格按照先进先出(FIFO)的原则进行消息发布和消费,即先发布的消息先消费,后发布的消息后消费。在 Apache RocketMQ 中支持分区顺序消息,如下图所示。我们可以按照某一个标准对消息进行分区(比如图中的ShardingKey),同一个ShardingKey的消息会被分配到同一个队列中,并按照顺序被消费。
 
+需要注意的是 RocketMQ 消息的顺序性分为两部分,生产顺序性和消费顺序性。只有同时满足了生产顺序性和消费顺序性才能达到上述的FIFO效果。
+
+**生产顺序性:** RocketMQ 通过生产者和服务端的协议保障单个生产者串行地发送消息,并按序存储和持久化。如需保证消息生产的顺序性,则必须满足以下条件:
+- 单一生产者: 消息生产的顺序性仅支持单一生产者,不同生产者分布在不同的系统,即使设置相同的分区键,不同生产者之间产生的消息也无法判定其先后顺序。
+- 串行发送:生产者客户端支持多线程安全访问,但如果生产者使用多线程并行发送,则不同线程间产生的消息将无法判定其先后顺序。
+
+满足以上条件的生产者,将顺序消息发送至服务端后,会保证设置了同一分区键的消息,按照发送顺序存储在同一队列中。服务端顺序存储逻辑如下:
+
 ![顺序消息发送](../picture/顺序消息发送.png)
 
-顺序消息的应用场景也非常广泛,比如在创建订单的例子中,需要保证同一个订单的生成、付款和发货,这三个操作被顺序执行。如果是普通消息,订单A的消息可能会被轮询发送到不同的队列中,不同队列的消息将无法保持顺序,而顺序消息发送时将ShardingKey相同(同一订单号)的消息序路由到一个逻辑队列中。
+顺序消息的应用场景也非常广泛,在有序事件处理、撮合交易、数据实时增量同步等场景下,异构系统间需要维持强一致的状态同步,上游的事件变更需要按照顺序传递到下游进行处理。
+
+例如创建订单的场景,需要保证同一个订单的生成、付款和发货,这三个操作被顺序执行。如果是普通消息,订单A的消息可能会被轮询发送到不同的队列中,不同队列的消息将无法保持顺序,而顺序消息发送时将ShardingKey相同(同一订单号)的消息序路由到一个逻辑队列中。
+![顺序消息场景一](../picture/顺序消息示例一.png)
 
 ## 顺序消息示例代码
 
@@ -58,6 +69,8 @@ public interface MessageQueueSelector {
 ```
 
 其中 mqs 是可以发送的队列,msg是消息,arg是上述send接口中传入的Object对象,返回的是该消息需要发送到的队列。上述例子里,是以orderId作为分区分类标准,对所有队列个数取余,来对将相同orderId的消息发送到同一个队列中。
+
+生产环境中建议选择最细粒度的分区键进行拆分,例如,将订单ID、用户ID作为分区键关键字,可实现同一终端用户的消息按照顺序处理,不同用户的消息无需保证顺序。
 :::
 
 
diff --git "a/docs/02-\347\224\237\344\272\247\350\200\205/07message3.md" "b/docs/02-\347\224\237\344\272\247\350\200\205/07message3.md"
index f8214a99..74b1502e 100644
--- "a/docs/02-\347\224\237\344\272\247\350\200\205/07message3.md"
+++ "b/docs/02-\347\224\237\344\272\247\350\200\205/07message3.md"
@@ -1,7 +1,13 @@
 # 延迟消息发送
 
+## 延时消息介绍
 延迟消息发送是指消息发送到Apache RocketMQ后,并不期望立马投递这条消息,而是延迟一定时间后才投递到Consumer进行消费。
 
+在分布式定时调度触发、任务超时处理等场景,需要实现精准、可靠的延时事件触发。使用 RocketMQ 的延时消息可以简化定时调度任务的开发逻辑,实现高性能、可扩展、高可靠的定时触发能力。
+
+![定时消息场景一](../picture/定时消息示例一.png)
+
+## 延时消息约束
 Apache RocketMQ 一共支持18个等级的延迟投递,具体时间如下:
 
 | 投递等级(delay level) | 延迟时间 | 投递等级(delay level) | 延迟时间  |
@@ -16,6 +22,7 @@ Apache RocketMQ 一共支持18个等级的延迟投递,具体时间如下:
 | 8                 | 4min | 17                | 1h    |
 | 9                 | 5min | 18                | 2h    |
 
+## 延时消息示例代码
 延迟消息的示例代码如下:
 
 ```javascript {10,11}
@@ -42,4 +49,8 @@ public class ScheduledMessageProducer {
 ```
 :::tip
 这里最重要的是message中设置延迟等级,例子中设置的等级是3,也就是发送者发送后,10s后消费者才能收到消息。
+:::
+
+:::tip
+延时消息的实现逻辑需要先经过定时存储等待触发,延时时间到达后才会被投递给消费者。因此,如果将大量延时消息的定时时间设置为同一时刻,则到达该时刻后会有大量消息同时需要被处理,会造成系统压力过大,导致消息分发延迟,影响定时精度。
 :::
\ No newline at end of file
diff --git "a/docs/02-\347\224\237\344\272\247\350\200\205/09message5.md" "b/docs/02-\347\224\237\344\272\247\350\200\205/09message5.md"
index e85ce461..a1fd2c5e 100644
--- "a/docs/02-\347\224\237\344\272\247\350\200\205/09message5.md"
+++ "b/docs/02-\347\224\237\344\272\247\350\200\205/09message5.md"
@@ -4,6 +4,18 @@
 
 在一些对数据一致性有强需求的场景,可以用 Apache RocketMQ  事务消息来解决,从而保证上下游数据的一致性。
 
+![事务消息示例一](../picture/事务消息示例一.png)
+
+以电商交易场景为例,用户支付订单这一核心操作的同时会涉及到下游物流发货、积分变更、购物车状态清空等多个子系统的变更。当前业务的处理分支包括:
+- 主分支订单系统状态更新:由未支付变更为支付成功。
+- 物流系统状态新增:新增待发货物流记录,创建订单物流记录。
+- 积分系统状态变更:变更用户积分,更新用户积分表。
+- 购物车系统状态变更:清空购物车,更新用户购物车记录。
+
+![事务消息示例一](../picture/事务示例二.png)
+
+使用普通消息和订单事务无法保证一致的原因,本质上是由于普通消息无法像单机数据库事务一样,具备提交、回滚和统一协调的能力。 而基于 RocketMQ 的分布式事务消息功能,在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。
+
 ![事务消息1](../picture/事务消息1.png)
 
 事务消息发送分为两个阶段。第一阶段会发送一个**半事务消息**,半事务消息是指暂不能投递的消息,生产者已经成功地将消息发送到了 Broker,但是Broker 未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,如果发送成功则执行本地事务,并根据本地事务执行成功与否,向 Broker 半事务消息状态(commit或者rollback),半事务消息只有 commit 状态才会真正向下游投递。如果由于网络闪断、生产者应用重启等原因,导致某条事务消息的二次确认丢失,Broker 端会通过扫描发现某条消息长期处于“半事务消息”时,需要主动向消息生产者询问该消息的最终状态(Commit或是Rollback)。这样最终保证了本地事务执行成功,下游就能收到消息,本地事务执行失败,下游就收不到消息。总而保证了上下游数据的一致性。
@@ -17,16 +29,18 @@
 事务消息**发送**步骤如下:
 
 1. 生产者将半事务消息发送至 `RocketMQ Broker`。
-2. `RocketMQ Broker` 将消息持久化成功之后,向生产者返回 Ack 确认消息已经发送成功,此时消息为半事务消息。
+2. `RocketMQ Broker` 将消息持久化成功之后,向生产者返回 Ack 确认消息已经发送成功,此时消息暂不能投递,为半事务消息。
 3. 生产者开始执行本地事务逻辑。
 4. 生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
 - 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。
 - 二次确认结果为Rollback:服务端将回滚事务,不会将半事务消息投递给消费者。
 5. 在断网或者是生产者应用重启的特殊情况下,若服务端未收到发送者提交的二次确认结果,或服务端收到的二次确认结果为Unknown未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。
 
+6. :::note 需要注意的是,服务端仅仅会按照参数尝试指定次数,超过次数后事务会强制回滚,因此未决事务的回查时效性非常关键,需要按照业务的实际风险来设置 :::
+
 事务消息**回查**步骤如下:
-1. 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
-2. 生产者根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。
+7. 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
+8. 生产者根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。
 
 ## 示例代码
 
diff --git "a/docs/picture/\344\272\213\345\212\241\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" "b/docs/picture/\344\272\213\345\212\241\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png"
new file mode 100644
index 00000000..52a864d7
Binary files /dev/null and "b/docs/picture/\344\272\213\345\212\241\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" differ
diff --git "a/docs/picture/\344\272\213\345\212\241\347\244\272\344\276\213\344\272\214.png" "b/docs/picture/\344\272\213\345\212\241\347\244\272\344\276\213\344\272\214.png"
new file mode 100644
index 00000000..058bd1f2
Binary files /dev/null and "b/docs/picture/\344\272\213\345\212\241\347\244\272\344\276\213\344\272\214.png" differ
diff --git "a/docs/picture/\345\256\232\346\227\266\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" "b/docs/picture/\345\256\232\346\227\266\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png"
new file mode 100644
index 00000000..ef95a90e
Binary files /dev/null and "b/docs/picture/\345\256\232\346\227\266\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" differ
diff --git "a/docs/picture/\351\241\272\345\272\217\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" "b/docs/picture/\351\241\272\345\272\217\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png"
new file mode 100644
index 00000000..a76cdd89
Binary files /dev/null and "b/docs/picture/\351\241\272\345\272\217\346\266\210\346\201\257\347\244\272\344\276\213\344\270\200.png" differ