

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Amazon MQ for RabbitMQ 最佳實踐
<a name="best-practices-rabbitmq"></a>

使用 Amazon MQ for RabbitMQ 代理程式時，請遵循這些生產就緒性準則，將代理程式效能最大化，並最佳化訊息輸送量效率。

**重要**  
目前，Amazon MQ 不支援[串流](https://www.rabbitmq.com/streams.html)，也無法在 RabbitMQ 3.9.x 中推出的 JSON 中使用結構化日誌記錄。

**Topics**
+ [Amazon MQ for RabbitMQ 中代理程式設定和連線管理的最佳實務](best-practices-broker-setup.md)
+ [Amazon MQ for RabbitMQ 中訊息耐用性和可靠性的最佳實務](best-practices-message-reliability.md)
+ [Amazon MQ for RabbitMQ 中效能最佳化和效率的最佳實務](best-practices-performance.md)
+ [Amazon MQ for RabbitMQ 中網路彈性和監控的最佳實務](best-practices-network-resilience.md)

# Amazon MQ for RabbitMQ 中代理程式設定和連線管理的最佳實務
<a name="best-practices-broker-setup"></a>

 中介裝置設定和連線管理是防止中介裝置訊息輸送量、資源使用率和處理生產工作負載能力問題的第一步。[建立和設定 Amazon MQ for RabbitMQ 代理程式](getting-started-rabbitmq.md#create-rabbitmq-broker)時，請完成下列最佳實務，以選取適當的執行個體類型、有效管理連線，以及設定訊息預先擷取以最大化代理程式的效能。

**重要**  
Amazon MQ for RabbitMQ 不支援使用者名稱「訪客」，並且會在您建立新的代理程式時刪除預設訪客帳戶。Amazon MQ 也會定期刪除任何客戶建立的帳戶，稱為「訪客」。

## 步驟 1：使用叢集部署
<a name="use-cluster-deployments-for-high-availability"></a>

 對於生產工作負載，我們建議使用叢集部署，而不是單一執行個體代理程式，以確保高可用性和訊息彈性。叢集部署會移除單一故障點，並提供更好的容錯能力。

 叢集部署由分佈在三個可用區域的三個 RabbitMQ 代理程式節點組成，提供自動容錯移轉，並確保即使整個可用區域無法使用，操作仍可繼續。Amazon MQ 會自動複寫所有節點的訊息，以確保節點故障或維護期間的可用性。

 叢集部署對於生產環境至關重要，並受 [Amazon MQ 服務水準協議](https://aws.amazon.com/amazon-mq/sla/)支援。

 如需詳細資訊，請參閱 [Amazon MQ for RabbitMQ 中的叢集部署](rabbitmq-broker-architecture.md#rabbitmq-broker-architecture-cluster)。

## 步驟 2：選擇正確的代理程式執行個體類型
<a name="choose-broker-instance-type"></a>

 代理程式執行個體類型的訊息輸送量取決於您的應用程式使用案例。 `M7g.medium`應僅用於測試應用程式效能。在生產環境中使用較大的執行個體之前，使用此較小的執行個體可以改善應用程式效能。在執行個體類型 `m7g.large` 和更高版本上，您可以使用叢集部署以獲得高可用性和訊息耐久性。較大的中介裝置執行個體類型可以處理用戶端和佇列的生產層級、高輸送量、記憶體中的訊息和備援訊息。

 如需選擇正確執行個體類型的詳細資訊，請參閱 [Amazon MQ for RabbitMQ 中的調整大小準則](rabbitmq-sizing-guidelines.md)。

## 步驟 3：使用規定人數佇列
<a name="use-quorum-queues"></a>

 對於 3.13 及更高版本的 RabbitMQ 代理程式，在生產環境中複寫佇列類型的預設選擇應該是使用叢集部署的配額佇列。配額佇列是一種現代複寫佇列類型，可提供高可靠性、高輸送量和穩定的延遲。

 配額佇列使用 Raft 共識演算法來提供更好的容錯能力。當領導節點無法使用時，仲裁佇列會自動透過多數投票來選擇新的領導，確保訊息傳遞以最小的中斷繼續。由於每個節點位於不同的可用區域，即使整個可用區域暫時無法使用，您的簡訊系統仍會保持可用狀態。

 若要宣告規定人數佇列，請在建立佇列`x-queue-type``quorum`時將 標頭設定為 。

 如需規定人數佇列的詳細資訊，包括遷移策略和最佳實務，請參閱 [Amazon MQ for RabbitMQ 中的規定人數佇列](quorum-queues.md)。

## 步驟 4：使用多個頻道
<a name="use-multiple-channels"></a>

 若要避免連線流失，請透過單一連線使用多個頻道。應用程式應避免 1：1 連線到頻道比率。我們建議針對每個程序使用一個連線，然後針對每個執行緒使用一個頻道。避免過度使用頻道，以防止頻道洩漏。

# Amazon MQ for RabbitMQ 中訊息耐用性和可靠性的最佳實務
<a name="best-practices-message-reliability"></a>

 將應用程式移至生產環境之前，請完成下列最佳實務，以防止訊息遺失和資源過度使用。

## 步驟 1：使用持久性訊息和持久性佇列
<a name="use-persistent-messages-durable-queues"></a>

 持久性訊息有助於在代理程式當機或重新啟動的情況下保護資料耐久性。持續性訊息會在送達磁碟時立即寫入。然而，與延遲佇列不同，除非代理程式需要更多記憶體，否則持續性訊息會在記憶體和磁碟中快取。在需要更多記憶體的情況下，訊息由管理將訊息儲存到磁碟的 RabbitMQ 代理程式機制從記憶體中刪除，通常稱為*持續性層*。

若要啟用訊息持續性，您可以將佇列宣告為 `durable`，並將訊息傳遞模式設定為 `persistent`。以下範例示範如何使用 [RabbitMQ Java 用戶端程式庫](https://www.rabbitmq.com/java-client.html)宣告耐久的佇列。使用 AMQP 0-9-1 時，您可以透過設定交付模式 "2"，將訊息標記為持久性。

```
boolean durable = true;
channel.queueDeclare("my_queue", durable, false, false, null);
```

 將佇列設定為耐久後，您可將 `MessageProperties` 設定為 `PERSISTENT_TEXT_PLAIN` (如以下範例所示)，將持續性訊息傳送到您的佇列。

```
import com.rabbitmq.client.MessageProperties;

channel.basicPublish("", "my_queue",
            MessageProperties.PERSISTENT_TEXT_PLAIN,
            message.getBytes());
```

## 步驟 2：設定發佈者確認和消費者交付確認
<a name="configure-confirmation-acknowledgement"></a>

 確認訊息已傳送至代理程式的程序稱為*發佈者確認*。發佈者確認讓應用程式知道訊息何時可靠地存放。發佈者確認也有助於控制存放在代理程式的訊息速率。如果沒有發佈者確認，則無法確認訊息已成功處理，而且您的代理程式可能會捨棄無法處理的訊息。

 同樣地，當用戶端應用程式將訊息的交付確認和取用傳回給代理程式時，稱為*消費者交付確認*。確認和確認對於確保使用 RabbitMQ 代理程式時的資料安全至關重要。

 消費者交付認可通常會設定於用戶端應用程式上。使用 AMQP 0-9-1 時，可以透過設定 `basic.consume`方法啟用確認。AMQP 0-9-1 用戶端也可以透過傳送 `confirm.select`方法來設定發佈者確認。

 通常，交付認可會在通道中啟用。例如，使用 RabbitMQ Java 用戶端程式庫時，您可使用 `Channel#basicAck` 來設定簡單的`basic.ack` 肯定認可，如以下範例所示。

```
// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // positively acknowledge a single delivery, the message will
             // be discarded
             channel.basicAck(deliveryTag, false);
         }
     });
```

**注意**  
 未認可的訊息必須在記憶體中快取。您可設定用戶端應用程式的[預先擷取](best-practices-performance.md#configure-prefetching)設定，以限制消費者預先擷取的訊息數量。

 您可以設定 `consumer_timeout`來偵測消費者何時不確認交付。如果消費者未在逾時值內傳送確認，則頻道將會關閉，而您將會收到 `PRECONDITION_FAILED`。若要診斷錯誤，請使用 [UpdateConfiguration](https://docs.aws.amazon.com/amazon-mq/latest/api-reference/configurations-configuration-id.html) API 來增加`consumer_timeout`值。

## 步驟 3：讓佇列保持簡短
<a name="keep-queues-short"></a>

在叢集部署中，具有大量訊息的佇列可能會導致資源過度使用。當代理程式過度使用時，重新啟動 Amazon MQ for RabbitMQ 代理程式可能會導致效能進一步降低。若已重新啟動，過度使用的代理程式可能會在 `REBOOT_IN_PROGRESS` 狀態中變得沒有回應。

在[維護時段](amazon-mq-rabbitmq-editing-broker-preferences.md#rabbitmq-edit-current-configuration-console)期間，Amazon MQ 會一次執行一個節點的所有維護工作，以確保代理程式維持運作狀態。因此，佇列可能需要在每個節點繼續操作時進行同步處理。在同步期間，需要複寫到鏡像的訊息會從對應的 Amazon Elastic Block Store (Amazon EBS) 磁碟區載入記憶體中，以便分批處理。分批處理訊息可讓佇列更快速地同步處理。

如果佇列保持簡短且訊息很小，則佇列會成功同步處理並繼續如預期般操作。不過，如果批次中的資料量接近節點的記憶體限制，節點就會引發高記憶體警示，暫停佇列同步。您可比較 `RabbitMemUsed` 與 `RabbitMqMemLimit` [CloudWatch 中的代理程式節點指標](amazon-mq-accessing-metrics.md)，以確認記憶體使用量。直到取用或刪除訊息或減少批次中的訊息數目，才能完成同步處理。

 如果叢集部署暫停佇列同步處理，建議您取用或刪除訊息，以減少佇列中的訊息數目。一旦佇列深度減少且佇列同步完成，代理程式狀態就會變更為 `RUNNING`。若要解決暫停的佇列同步，您也可套用政策以[降低佇列同步處理批次大小](rabbitmq-queue-sync.md)。

您也可以定義自動刪除和 TTL 政策，以主動減少資源用量，並將消費者NACKs 保持在最低限度。在代理程式上重新排入佇列訊息是 CPU 密集型，因此大量的 NACKs 可能會影響代理程式效能。

# Amazon MQ for RabbitMQ 中效能最佳化和效率的最佳實務
<a name="best-practices-performance"></a>

 您可以將 Amazon MQ for RabbitMQ 代理程式效能最佳化，方法是將輸送量最大化、將延遲降至最低，並確保有效率的資源使用率。完成下列最佳實務以最佳化您的應用程式效能。

## 步驟 1：將訊息大小保持在 1 MB 以下
<a name="keep-messages-under-one-mb"></a>

 我們建議將訊息保持在 1 MB (MB) 以下，以獲得最佳效能和可靠性。

 RabbitMQ 3.13 預設支援高達 128 MB 的訊息大小，但大型訊息可能會觸發無法預測的記憶體警示，封鎖發佈並可能建立高記憶體壓力，同時跨節點複寫訊息。過大的訊息也可能會影響代理程式重新啟動和復原程序，這會提高服務持續性的風險，並可能導致效能降低。

 **使用宣告檢查模式存放和擷取大型承載** 

 若要管理大型訊息，您可以將訊息承載儲存在外部儲存體中，並僅透過 RabbitMQ 傳送承載參考識別符，以實作宣告檢查模式。消費者使用承載參考識別符來擷取和處理大型訊息。

 下圖示範如何使用 Amazon MQ for RabbitMQ 和 Amazon S3 實作宣告檢查模式。

![\[Diagram showing data flow between Producer, Consumer, Amazon MQ broker, and AWS S3.\]](http://docs.aws.amazon.com/zh_tw/amazon-mq/latest/developer-guide/images/claim-check-pattern.png)


 下列範例示範此模式使用 Amazon MQ、[AWS 適用於 Java 的 SDK 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html) 和 [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)：

1.  首先，定義將保留 Amazon S3 參考識別碼的訊息類別。

   ```
   class Message {
       // Other data fields of the message...
   
       public String s3Key;
       public String s3Bucket;
   }
   ```

1.  建立發佈者方法，將承載存放在 Amazon S3 中，並透過 RabbitMQ 傳送參考訊息。

   ```
   public void publishPayload() {
       // Store the payload in S3.
       String payload = PAYLOAD;
       String prefix = S3_KEY_PREFIX;
       String s3Key = prefix + "/" + UUID.randomUUID();
       s3Client.putObject(PutObjectRequest.builder()
           .bucket(S3_BUCKET).key(s3Key).build(), 
           RequestBody.fromString(payload));
       
       // Send the reference through RabbitMQ.
       Message message = new Message();
       message.s3Key = s3Key;
       message.s3Bucket = S3_BUCKET;
       // Assign values to other fields in your message instance.
   
       publishMessage(message);
   }
   ```

1.  實作取用者方法，從 Amazon S3 擷取承載、處理承載，以及刪除 Amazon S3 物件。

   ```
   public void consumeMessage(Message message) {
       // Retrieve the payload from S3.
       String payload = s3Client.getObjectAsBytes(GetObjectRequest.builder()
           .bucket(message.s3Bucket).key(message.s3Key).build())
           .asUtf8String();
       
       // Process the complete message.
       processPayload(message, payload);
       
       // Delete the S3 object.
       s3Client.deleteObject(DeleteObjectRequest.builder()
           .bucket(message.s3Bucket).key(message.s3Key).build());
   }
   ```

## 步驟 2：使用 `basic.consume`和長期消費者
<a name="use-basic-consume"></a>

 `basic.consume` 搭配長期消費者使用 比使用 輪詢個別訊息更有效率`basic.get`。如需詳細資訊，請參閱[輪詢個別訊息](https://www.rabbitmq.com/docs/3.13/consumers#polling)。

## 步驟 3：設定預先擷取
<a name="configure-prefetching"></a>

 您可以使用 RabbitMQ 預先擷取值來最佳化消費者取用訊息的方式。RabbitMQ 可將預先擷取計數應用到取消費者而不是通道，以實作 AMQP 0-9-1 提供的通道預先擷取機制。預先擷取值用於指定在任何給定的時間傳送給消費者的訊息數量。根據預設，RabbitMQ 會為用戶端應用程式設定不受限的緩衝區大小。

 為 RabbitMQ 消費者設定預先擷取計數時，需要考量各種因素。首先，請考量消費者的環境和組態。因為消費者需要在處理時讓所有訊息保留在記憶體中，因此高預先擷取值可能會對消費者的效能產生負面影響，在某些情況下，可能會導致消費者可能一起當機。同樣地，RabbitMQ 代理程式本身會讓其傳送的所有訊息保持在記憶體中快取，直到其收到消費者認可為止。如果沒有為消費者設定自動認可，且消費者花相對長的時間來處理訊息，則高預先擷取值可能會導致 RabbitMQ 伺服器快速耗盡記憶體。

考慮到上述考量，我們建議一律設定預先擷取值，以防止 RabbitMQ 代理程式或其消費者因大量未處理或未認可的訊息而耗盡記憶體的情況。如果您需要將代理程式最佳化以處理大量訊息，您可使用一系列預先擷取計數來測試代理程式和消費者，以判斷相較於消費者處理訊息所需的時間，網路負荷在哪個時候變得非常微不足道的值。

**注意**  
如果用戶端應用程式已設定為自動認可訊息傳遞給消費者，則設定預先擷取值沒有作用。
所有預先擷取的訊息會從佇列中移除。

以下範例示範如何使用 RabbitMQ Java 用戶端程式庫，為單一消費者設定 `10` 的預先擷取值。

```
ConnectionFactory factory = new ConnectionFactory();

Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

channel.basicQos(10, false);

QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume("my_queue", false, consumer);
```

**注意**  
在 RabbitMQ Java 用戶端程式庫中，`global` 旗標的預設值會設為 `false`，所以上述範例可以簡單地撰寫為 `channel.basicQos(10)`。

## 步驟 4：搭配規定人數佇列使用 Celery 5.5 或更新版本
<a name="use-celery-with-quorum-queues"></a>

 [Python Celery](https://docs.celeryq.dev/en/stable/index.html) 是分散式任務佇列系統，可在遇到高任務負載時產生許多非關鍵訊息。這項額外的代理程式活動可能會觸發[Amazon MQ for RabbitMQ：高記憶體警示](troubleshooting-action-required-codes-rabbitmq-memory-alarm.md)並導致代理程式無法使用。若要降低觸發記憶體警示的機會，請執行下列動作：

**對於所有 Celery 版本**

1. 關閉 [https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_create_missing_queues](https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_create_missing_queues) 以減輕佇列流失。

1.  然後，關閉 `worker_enable_remote_control`以停止動態建立`celery@...pidbox`佇列。這將減少代理程式上的佇列流失。

   ```
   worker_enable_remote_control = false
   ```

1.  若要進一步減少非關鍵訊息活動，請在啟動 Celery 應用程式時，透過不包含 `-E`或 `--task-events`旗標來關閉 Celery [worker-send-task-events](https://docs.celeryq.dev/en/stable/userguide/configuration.html#worker-send-task-events)。

1.  使用下列參數啟動您的 Celery 應用程式：

   ```
   celery -A app_name worker --without-heartbeat --without-gossip --without-mingle
   ```

**對於 Celery 5.5 版及更新版本**

1.  升級至 [Celery 5.5 版](https://docs.celeryq.dev/en/latest/changelog.html#version-5-5-0)、支援規定人數佇列的最低版本，或更新版本。若要檢查您正在使用的 Celery 版本，請使用 `celery --version`。如需規定人數佇列的詳細資訊，請參閱 [Amazon MQ 上 RabbitMQ 的配額佇列 Amazon MQ](quorum-queues.md)。

1.  升級至 Celery 5.5 或更新版本之後，`task_default_queue_type`請將 設定為[「規定人數」](https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_default_queue_type)。

1.  然後，您還必須在[中介裝置傳輸選項](https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-broker_transport_options)中開啟發佈確認：

   ```
   broker_transport_options = {"confirm_publish": True}
   ```

# Amazon MQ for RabbitMQ 中網路彈性和監控的最佳實務
<a name="best-practices-network-resilience"></a>

 網路彈性和監控代理程式指標對於維護可靠的簡訊應用程式至關重要。完成下列最佳實務，以實作自動復原機制和資源監控策略。

## 步驟 1：從網路故障自動復原
<a name="automatically-recover-from-network-failures"></a>

我們建議一律啟用自動網路復原，以避免在用戶端連線到 RabbitMQ 節點失敗的情況下發生重大停機。從版本 `4.0.0` 開始，RabbitMQ Java 用戶端程式庫預設支援自動網路復原。

如果連線的 I/O 迴圈中擲回未處理的例外狀況、如果偵測到通訊端讀取作業逾時，或者伺服器遺漏[活動訊號](https://www.rabbitmq.com/heartbeats.html)，就會觸發自動連線復原。

在用戶端與 RabbitMQ 節點之間的初始連線失敗的情況下，將不會觸發自動復原。我們建議您透過重試連線來撰寫應用程式程式碼，以解決初始連線失敗的問題。以下範例示範如何使用 RabbitMQ Java 用戶端程式庫重試初始網路故障。

```
ConnectionFactory factory = new ConnectionFactory();
// enable automatic recovery if using RabbitMQ Java client library prior to version 4.0.0.
factory.setAutomaticRecoveryEnabled(true);
// configure various connection settings

try {
  Connection conn = factory.newConnection();
} catch (java.net.ConnectException e) {
  Thread.sleep(5000);
  // apply retry logic
}
```

**注意**  
如果應用程式使用 `Connection.Close` 方法關閉連線，則不會啟用或觸發自動網路復原。

## 步驟 2：監控代理程式指標和警示
<a name="monitor-metrics-alarms"></a>

 我們建議您定期監控 Amazon MQ for RabbitMQ 代理程式的 [CloudWatch 指標](amazon-mq-accessing-metrics.md)和警示，以便在潛在問題影響您的簡訊應用程式之前加以識別和解決。主動監控對於維護彈性傳訊應用程式並確保最佳效能至關重要。

 Amazon MQ for RabbitMQ 會將指標發佈至 CloudWatch，以深入了解中介裝置效能、資源使用率和訊息流程。要監控的關鍵指標包括記憶體用量和磁碟用量。您可以在代理程式接近資源限制或效能降低時設定 [CloudWatch 警示](https://docs.aws.amazon.com/Ihttps://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Alarm-On-Metrics.html)。

監控下列基本指標：

**`RabbitMQMemUsed` 和 `RabbitMQMemLimit`**  
監控記憶體用量，以防止可能封鎖訊息發佈的記憶體警示。

**`RabbitMQDiskFree` 和 `RabbitMQDiskFreeLimit`**  
監控磁碟用量，以避免可能導致代理程式故障的磁碟空間問題。

 對於叢集部署， 也會監控[節點特定的指標](rabbitmq-logging-monitoring.md#security-logging-monitoring-cloudwatch-destination-metrics-rabbitmq)，以識別節點特定的問題。

**注意**  
如需如何防止高記憶體警示的詳細資訊，請參閱[解決和防止高記憶體警示](troubleshooting-action-required-codes-rabbitmq-memory-alarm.md#address-prevent-high-memory-alarm)。