

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

# Amazon SQS 暫時佇列
<a name="sqs-temporary-queues"></a>

使用常見的訊息模式 (例如*要求-回應*) 時，暫存佇列可協助您節省開發時間和部署成本。您可以使用[暫存佇列用戶端](https://github.com/awslabs/amazon-sqs-java-temporary-queues-client)來建立高輸送量、符合成本效益的應用程式管理暫存佇列。

用戶端會自動將多個*臨時佇列*映射至單一 Amazon SQS 佇列，即根據特定程序需求建立的應用程式受管佇列。如此可讓您的應用程式減少 API 呼叫次數，並在各暫時佇列的流量變低時提高輸送量。不再使用暫時佇列時，用戶端會自動清除暫時佇列，即使使用用戶端的部分處理序未完全關閉。

以下是暫時佇列的優點：
+ 它們可以做為特定執行緒或處理序的輕量型通訊頻道。
+ 不須額外費用，即可建立並刪除它們。
+ 它們是相容於靜態 (一般) Amazon SQS 佇列的 API。這表示傳送與接收訊息的現有程式碼可以傳送訊息至虛擬佇列，並接收來自虛擬佇列的訊息。

## 虛擬佇列
<a name="virtual-queues"></a>

*虛擬佇列*是暫時佇列用戶端建立的本機資料結構。虛擬佇列可讓您將多個流量不足的目的地合併成單一 Amazon SQS 佇列。如需最佳實務，請參閱避免在虛擬佇列中重複使用相同的訊息群組 ID。

**注意**  
建立虛擬佇列時，只會為消費者建立接收訊息的暫時資料結構。由於虛擬佇列不會進行 Amazon SQS 的 API 呼叫，因此虛擬佇列不須任何費用。
TPS 配額會套用到單一主機佇列中的所有虛擬佇列。如需詳細資訊，請參閱 [Amazon SQS 訊息配額](quotas-messages.md)。

`AmazonSQSVirtualQueuesClient` 包裝類別新增對於虛擬佇列相關的屬性支援。若要建立虛擬佇列，您必須使用 `HostQueueURL` 屬性呼叫 `CreateQueue` API 動作。此屬性指定託管虛擬佇列的現有佇列。

虛擬佇列的 URL 採用下列格式。

```
https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue#MyVirtualQueueName
```

生產者呼叫虛擬佇列 URL 上的 `SendMessage` 或 `SendMessageBatch` API 動作時，暫時佇列用戶端會執行下列動作：

1. 擷取虛擬佇列名稱。

1. 將虛擬佇列名稱做為其他訊息名稱連接。

1. 傳送訊息至託管佇列。

生產者傳送訊息時，背景執行緒會輪詢託管佇列，然後根據對應的訊息屬性將已接收的訊息傳送至虛擬佇列。

消費者呼叫虛擬佇列 URL 上的 `ReceiveMessage` API 動作時，暫時佇列用戶端便會在本機封鎖呼叫，直到背景執行緒傳送訊息至虛擬佇列。(此程序與[緩衝處理過的非同步用戶端](sqs-client-side-buffering-request-batching.md)中的訊息預先提取相似：單一 API 動作最多可以提供訊息給 10 個虛擬佇列。) 刪除虛擬佇列時，會移除任何用戶端側資源，不會自行呼叫 Amazon SQS。

`AmazonSQSTemporaryQueuesClient` 類別會自動將其建立的所有佇列轉成暫時佇列。它還會自動依需求建立佇列屬性相同的託管佇列。這些佇列的名稱共用常見、可設定的字首 (預設為 `__RequesterClientQueues__`)，藉以表明為暫時佇列。這可讓用戶端做為便利替代方案，將建立與刪除佇列的現有程式碼最佳化。用戶端也包括允許佇列間雙向通訊的 `AmazonSQSRequester` 和 `AmazonSQSResponder` 介面。

## 請求-回應訊息模式 (虛擬佇列)
<a name="request-reply-messaging-pattern"></a>

暫時佇列最常見的使用案例是*請求-回應*訊息模式，其中請求者會建立用於接收各回應訊息的*暫時佇列*。為了避免各回應訊息都會建立 Amazon SQS 佇列，暫時佇列用戶端可讓您建立與刪除多個暫時佇列，而無須進行任何 Amazon SQS API 呼叫。如需詳細資訊，請參閱實作請求-回應系統。

下圖顯示使用此模式的常見組態。

![搭配 Amazon SQS 使用的請求-回應模式圖。](http://docs.aws.amazon.com/zh_tw/AWSSimpleQueueService/latest/SQSDeveloperGuide/images/sqs-request-response-pattern.png)


## 範例情況：處理登入請求
<a name="example-scenario"></a>

以下範例情況顯示如何使用 `AmazonSQSRequester` 和 `AmazonSQSResponder` 介面來處理使用者的登入請求。

### 在用戶端
<a name="process-login-request-client-side"></a>

```
public class LoginClient {

    // Specify the Amazon SQS queue to which to send requests.
    private final String requestQueueUrl;

    // Use the AmazonSQSRequester interface to create
    // a temporary queue for each response.
    private final AmazonSQSRequester sqsRequester = 
            AmazonSQSRequesterClientBuilder.defaultClient();

    LoginClient(String requestQueueUrl) {
        this.requestQueueUrl = requestQueueUrl;
    }

    // Send a login request.
    public String login(String body) throws TimeoutException {
        SendMessageRequest request = new SendMessageRequest()
                .withMessageBody(body)
                .withQueueUrl(requestQueueUrl);

        // If no response is received, in 20 seconds,
        // trigger the TimeoutException.
        Message reply = sqsRequester.sendMessageAndGetResponse(request, 
                20, TimeUnit.SECONDS);

        return reply.getBody();
    }
}
```

傳送登入請時，會進行下列動作：

1. 建立暫時佇列。

1. 將暫時佇列的 URL 連接至做為屬性的訊息。

1. 傳送訊息。

1. 接收來自暫時佇列的回應。

1. 刪除暫時佇列。

1. 傳回回應。

### 在伺服器端
<a name="process-login-request-server-side"></a>

以下範例假設在建構後，便會建立執行緒來輪詢佇列並呼叫各訊息的`handleLoginRequest()` 方法，此外，`doLogin()` 為假設的方法。

```
public class LoginServer {

    // Specify the Amazon SQS queue to poll for login requests.
    private final String requestQueueUrl;

    // Use the AmazonSQSResponder interface to take care
    // of sending responses to the correct response destination.
    private final AmazonSQSResponder sqsResponder = 
            AmazonSQSResponderClientBuilder.defaultClient();

    LoginServer(String requestQueueUrl) {
        this.requestQueueUrl = requestQueueUrl;
    }

    // Process login requests from the client.
    public void handleLoginRequest(Message message) {

        // Process the login and return a serialized result.
        String response = doLogin(message.getBody());

        // Extract the URL of the temporary queue from the message attribute
        // and send the response to the temporary queue.
        sqsResponder.sendResponseMessage(MessageContent.fromMessage(message), 
                new MessageContent(response));  
    }
}
```

## 清除佇列
<a name="cleaning-up-queues"></a>

若要確保 Amazon SQS 會回收虛擬佇列所使用的任何記憶體內資源，當您的應用程式不再需要暫時佇列用戶端時，它應呼叫 `shutdown()` 方法。您也可以使用 `AmazonSQSRequester` 介面的 `shutdown()` 方法。

暫時佇列用戶端也提供消除遺棄的託管佇列的方法。對於會在一段期間 (預設為 5 分鐘) 內接收 API 呼叫的各佇列而言，用戶端會使用 `TagQueue` API 動作來標記仍在使用中的佇列。

**注意**  
任何在佇列上採取的 API 動作都會把它標記為非閒置，包括不會傳回訊息的 `ReceiveMessage` 動作。

背景執行緒使用 `ListQueues` 和 `ListTags` API 動作來檢查包含已設定字首的所有佇列，刪除至少五分鐘未被標記的任何佇列。依此方式，如果一個用戶端未完全關閉，其他作用中用戶端會在之後清除。為減少工作重複，字首相同的所有用戶端都會透過以該字首命名的共用內部工作佇列進行通訊。