匯出 (0) 列印
全部展開

使用 Service Bus 代理訊息改善效能的最佳作法

更新日期: 2014年6月

本主題說明如何在交換代理訊息時利用 Microsoft Azure 服務匯流排 達到最佳效能。本主題的前半部說明為了協助提高效能所提供的各種機制。後半部則提供如何使用 服務匯流排 為指定的案例提供最佳效能的指引。

在這一整個主題中,「用戶端」一詞是指可存取 服務匯流排 的任何實體。用戶端可以擔任傳送者或接收者的角色。「傳送者」一詞用於將訊息傳送至 服務匯流排 佇列或主題的 服務匯流排 佇列或主題用戶端。「接收者」一詞是指從 服務匯流排 佇列或訂閱接收訊息的 服務匯流排 佇列或訂閱用戶端。

本節介紹 服務匯流排 用於協助提升效能的各種概念。

服務匯流排 可讓用戶端透過兩個通訊協定傳送和接收訊息:服務匯流排 用戶端通訊協定和 HTTP。服務匯流排 用戶端通訊協定比較有效率,因為只要訊息 Factory 存在,它就會保持 服務匯流排 服務連線。此外,還會實作批次處理和預先擷取作業。服務匯流排 用戶端通訊協定適用於使用 .NET Managed API 的 .NET 應用程式。

除非明確提到,否則本主題中的所有內容均假設使用 服務匯流排 用戶端通訊協定。

服務匯流排 用戶端物件 (如 QueueClientMessageSender) 是透過 MessagingFactory 物件 (也用來提供連線的內部管理) 所建立。您不能在傳送訊息之後,關閉訊息 Factory 或佇列、主題與訂閱用戶端,然後在傳送下一則訊息時重建這些 Factory 和用戶端。關閉訊息 Factory 會刪除 服務匯流排 服務連線,並且在重建 Factory 時建立新連線。建立連線是一項耗費資源的作業,將相同的 Factory 和用戶端物件重複使用於多項作業,即可加以避免。

執行作業 (Send、Receive、Delete 等) 需要一點時間。除了要求和回覆的延遲以外,此時間還包含 服務匯流排 服務的作業處理時間。若要增加每次的作業數目,則必須並行執行作業。您可以使用數種方法來達到此目的:

  • 非同步作業:透過執行非同步作業的用戶端管道作業。下一個要求會在前一個要求完成之前開始。下列是非同步 Send 作業的範例:

    BrokeredMessage m1 = new BrokeredMessage(body);
    BrokeredMessage m2 = new BrokeredMessage(body);
    queueClient.BeginSend(m1, processEndSend, queueClient); // Send message 1.
    queueClient.BeginSend(m2, processEndSend, queueClient); // Send message 2.
    
    void processEndSend(IAsyncResult result)
    {
        QueueClient qc = result.AsyncState as QueueClient;
        qc.EndSend(result);
        Console.WriteLine("Message sent");
    }
    
    下列是非同步 Receive 作業的範例:

    queueClient.BeginReceive(processEndReceive, queueClient); // Receive message 1.
    queueClient.BeginReceive(processEndReceive, queueClient); // Receive message 2.
    
    void processEndReceive(IAsyncResult result) 
    {
        QueueClient qc = result.AsyncState as QueueClient;
        BrokeredMessage m = qc.EndReceive(result);
        m.BeginComplete(processEndComplete, m);
        Console.WriteLine("Received message " + m.Label);
    }
    
    void processEndComplete(IAsyncResult result)
    {
        BrokeredMessage m = result.AsyncState as BrokeredMessage;
        m.EndComplete(result);
        Console.WriteLine("Completed message " + m.Label);
    }
    
  • 多個 Factory:相同 Factory 建立的所有用戶端 (不只是接收者,還包括傳送者) 會共用一個 TCP 連線。最大訊息輸送量受限於可通過此 TCP 連線的作業數目。可透過單一 Factory 取得的輸送量,會隨著 TCP 來回行程時間和訊息大小大幅改變。若要獲得較高的輸送量速率,您必須使用多個訊息 Factory。

您可以在建立佇列或訂閱用戶端時,指定接收模式:Peek-lockReceive and delete。預設接收模式為 PeekLock。在此模式下作業時,用戶端會傳送要求以接收來自 服務匯流排 的訊息。用戶端會在接收訊息之後,傳送要求以完成訊息。

若將接收模式設定為 ReceiveAndDelete,則會在單一要求中結合這兩個步驟。這會減少整體的作業數目,並可改善整體訊息輸送量。此效能增益具有遺失訊息的風險。

服務匯流排 不支援 Receive-And-Delete 作業的交易。此外,在用戶端想要延遲訊息或使訊息無法傳送的所有案例中,都需要 peek-lock 語意。

用戶端批次處理可讓佇列或主題用戶端將訊息的傳送延遲一段時間。如果用戶端在這段時間內傳送其他訊息,則會以單一批次傳輸訊息。用戶端批次處理也會導致佇列/訂閱用戶端將多個 Complete 要求批次處理成單一要求。批次處理僅適用於非同步 SendComplete 作業。同步作業會立即傳送至 服務匯流排 服務。不是每一項 Peek 或 Receive 作業都會進行批次處理,而且也不是所有用戶端都會進行批次處理。

如果批次超過訊息大小上限,則會移除批次中的最後一則訊息,而且用戶端會立即傳送此批次。最後一則訊息會成為下一個批次的第一則訊息。根據預設,用戶端使用的批次間隔為 20 毫秒。在建立訊息 Factory 之前設定 BatchFlushInterval 屬性,即可變更批次間隔。此設定會影響此 Factory 建立的所有用戶端。若要停用批次處理,請將 BatchFlushInterval 屬性設定為 TimeSpan.Zero。例如:

MessagingFactorySettings mfs = new MessagingFactorySettings();
mfs.TokenProvider = tokenProvider;
mfs.NetMessagingTransportSettings.BatchFlushInterval = TimeSpan.FromSeconds(0.05);
MessagingFactory messagingFactory = MessagingFactory.Create(namespaceUri, mfs);

批次處理不會影響可計費的訊息作業數目,而且僅適用於 服務匯流排 用戶端通訊協定。HTTP 通訊協定不支援批次處理。

為了提高佇列/主題/訂閱的輸送量,服務匯流排 服務會在寫入其內部存放區時將多則訊息批次處理。如果已在佇列或主題上啟用批次處理,則將訊息寫入存放區時會進行批次處理。如果已在佇列或訂閱上啟用批次處理,則從存放區刪除訊息時會進行批次處理。如果已對某個實體啟用批次存放區存取,則 服務匯流排 最多可將與該實體有關的存放區寫入作業延遲 20 毫秒。此間隔期間內發生的其他存放區作業都會加入到此批次。批次存放區存取只會影響 SendComplete 作業;Receive 作業則不受影響。批次存放區存取是實體的屬性。啟用批次存放區存取的實體都會進行批次處理。

建立新佇列、主題或訂閱時,預設會啟用批次存放區存取。若要停用批次存放區存取,請在建立實體之前,將 EnableBatchedOperations 屬性設定為 false。例如:

QueueDescription qd = new QueueDescription();
qd.EnableBatchedOperations = false;
Queue q = namespaceManager.CreateQueue(qd);

批次存放區存取是佇列、主題或訂閱的屬性,並不會影響可計費的訊息作業數目。它與接收模式及用戶端與 服務匯流排 服務之間所用的通訊協定無關。

預先擷取可讓佇列或訂閱用戶端在執行 Receive 作業時,載入服務的其他訊息。用戶端會將這些訊息儲存在本機快取中。快取大小是由 PrefetchCountPrefetchCount 屬性所決定。啟用預先擷取的每個用戶端都會維護自己的快取。快取不會由所有用戶端共用。如果用戶端起始 Receive 作業且其快取是空的,則服務會傳輸一批訊息。批次大小等於快取大小或 256KB (兩者之中較小者)。如果用戶端起始 Receive 作業且快取包含一則訊息,則會從快取取得此訊息。

預先擷取訊息時,服務會鎖定預先擷取的訊息。如此一來,其他接收者便無法接收預先擷取的訊息。如果接收者無法在鎖定到期前完成訊息,此訊息則可供其他接收者使用。預先擷取的訊息副本會保留在快取中。採用已到期之快取副本的接收者會在嘗試完成訊息時,收到例外況狀。根據預設,訊息鎖定會在 60 秒之後到期。此值可延長為 5 分鐘。若要避免採用過期的訊息,快取大小必須永遠小於用戶端在鎖定逾時間隔內可採用的訊息數目。

使用 60 秒的預設鎖定到期時,SubscriptionClient.PrefetchCount 的理想值是 20 乘以 Factory 之所有接收者的最大處理速率。例如,Factory 建立 3 個接收者。每個接收者每秒最多可處理 10 則訊息。預先擷取計數應不超過 20*3*10 = 600。根據預設,QueueClient.PrefetchCount 會設定為 0,這表示不會從服務擷取任何其他訊息。

預先擷取訊息會提高佇列或訂閱的整體輸送量,因為此舉可降低訊息作業或來回行程的整體數目。但是,擷取第一則訊息需要比較長的時間 (由於訊息大小增加)。接收預先擷取的訊息比較快速,因為用戶端已經下載了這些訊息。

伺服器將訊息傳送至用戶端時,會檢查該訊息的存留時間 (TTL) 屬性。但用戶端不會在接收訊息時檢查該訊息的 TTL 屬性。在用戶端快取訊息時,即使已超過該訊息的 TTL,仍可接收該資訊。

預先擷取不會影響可計費的訊息作業數目,而且僅適用於 服務匯流排 用戶端通訊協定。HTTP 通訊協定不支援預先擷取。預先擷取適用於同步和非同步 Receive 作業。

快速實體會啟用高輸送量和減少延遲案例。使用快速實體時,如果訊息已傳送到佇列或主題,則不會立即儲存在訊息存放區中。而是將訊息快取到記憶體中。如果訊息仍然在佇列中多停留數秒,則會自動寫入到靜態儲存體,藉此保護訊息免於中斷而遺失。將訊息寫入至記憶體快取,會增加輸送量以及減少延遲,因為傳送訊息時不會存取靜態儲存體。維持數秒的訊息不會寫入訊息存放區。下列範例會建立快速主題:

TopicDescription td = new TopicDescription(TopicName);
td.EnableExpress = true;
namespaceManager.CreateTopic(td);

如果將含有不得遺失的重要資訊的訊息傳送至快速實體,則傳送者可以強制 服務匯流排 將訊息立即保留至靜態儲存體,方法是將 ForcePersistence 屬性設定為 true.如需詳細資訊,請參閱 Azure SDK 2.3 版本 (2014 年 4 月) 的新功能

或者,服務匯流排 會使用相同的節點和訊息儲存區來處理和儲存所有訊息實體訊息 (佇列或主題)。此外,磁碟分割佇列或主題,已跨多個節點和訊息儲存區分散。磁碟分割佇列和主題不僅會產生比一般佇列和主題更高的輸送量,也會顯示優異的可用性。若要建立磁碟分割實體,設定 EnablePartitioning 屬性為 true,如下列範例中所示。如需以下內容的詳細資訊磁碟分割實體,請參閱分割訊息實體

// Create partitioned queue.
QueueDescription qd = new QueueDescription(QueueName);
qd.EnablePartitioning = true;
namespaceManager.CreateQueue(qd);

如果無法使用磁碟分割佇列或主題,或預期的載入無法由單一的磁碟分割佇列或主題處理,您必須使用多個訊息實體。使用多個實體時,必須針對每個實體建立專屬用戶端,而非將相同的用戶端運用於所有實體。

下列各節描述典型的訊息案例,並簡述慣用的 服務匯流排 設定。輸送量速率可分為低 (<1msg/s)、中 (≥1msg/s、<100msg/s)、高 (≥100msg/s)。用戶端數目可分為小 (≤5)、中 (>5、≤20)、大 (>20)。

目標:單一佇列的最大輸送量。傳送者和接收者的數目很小。

  • 使用磁碟分割佇列以改善效能和可用性。

  • 若要提高傳送到佇列的整體速率,請使用多個訊息 Factory 來建立傳送者。針對每一個傳送者,使用非同步作業或多個執行緒。

  • 若要提高從佇列接收的整體速率,請使用多個訊息 Factory 來建立接收者。

  • 使用非同步作業,以便利用用戶端批次處理。

  • 將批次處理間隔設定為 50 毫秒,即可減少 服務匯流排 用戶端通訊協定傳輸數目。如果使用了多個傳送者,請將批次處理間隔提高為 100 毫秒。

  • 讓批次存放區存取保持啟用狀態。這會提高訊息寫入佇列的整體速率。

  • 將預先擷取計數設定為 20 乘以 Factory 之所有接收者的最大處理速率。這會減少 服務匯流排 用戶端通訊協定傳輸數目。

目標:多個佇列的最大整體輸送量。個別佇列的輸送量為「中」或「高」。

若要使多個佇列達到最大輸送量,請使用簡述的設定將單一佇列的輸送量最大化。此外,請使用不同 Factory 來建立可傳送至或接收自不同佇列的用戶端。

目標:最小化佇列或主題的端對端延遲。傳送者和接收者的數目很小。佇列的輸送量為「低」或「中」。

  • 使用磁碟分割佇列以改善可用性。

  • 停用用戶端批次處理。用戶端會立即傳送訊息。

  • 停用批次存放區存取。服務會立即將訊息寫入存放區。

  • 如果使用單一用戶端,請將預先擷取計數設定為 20 乘以接收者的處理速率。如果有多則訊息同時抵達佇列,則 服務匯流排 用戶端通訊協定會同時傳輸全部訊息。當用戶端收到下一則訊息時,該訊息已經在本機快取中。此快取必須很小。

  • 如果使用多個用戶端,請將預先擷取計數設定為 0。如此一來,第二個用戶端即可在第一個用戶端仍在處理第一則訊息時,接收第二則訊息。

目標:將具有大量傳送者之佇列或主題的輸送量最大化。每個傳送者都是以中等速率傳送訊息。接收者的數目很小。

服務匯流排 可讓實體最多擁有100 個並行連線。若為佇列,此數字則是由傳送者和接收者共用。如果傳送者需要全部 100 個連線,您必須以主題和單一訂閱取代此佇列。一個主題最多可接受來自傳送者的 100 個並行連線,而訂閱可接受來自接收者的額外 100 個並行連線。如果需要超過 100 個並行傳送者,則傳送者必須透過 HTTP 將訊息傳送至 服務匯流排 通訊協定。

若要將輸送量最大化,請執行下列動作:

  • 使用磁碟分割佇列以改善效能和可用性。

  • 如果傳送者位於不同的處理程序中,則每一個處理程序僅使用單一 Factory。

  • 使用非同步作業,以便利用用戶端批次處理。

  • 使用預設批次處理間隔 20 毫秒,即可減少 服務匯流排 用戶端通訊協定傳輸數目。

  • 讓批次存放區存取保持啟用狀態。這會提高訊息寫入佇列或主題的整體速率。

  • 將預先擷取計數設定為 20 乘以 Factory 之所有接收者的最大處理速率。這會減少 服務匯流排 用戶端通訊協定傳輸數目。

目標:將具有大量接收者之佇列或訂閱的接收率最大化。每個接收者都是以中等速率接收訊息。傳送者的數目很小。

服務匯流排 可讓實體最多擁有100 個並行連線。如果佇列需要超過 100 個接收者,您必須以主題和多個訂閱取代此佇列。每個訂閱最多可支援 100 個並行連線。此外,接收者可透過 HTTP 通訊協定存取佇列。


若要將輸送量最大化,請執行下列動作:

  • 使用磁碟分割佇列以改善效能和可用性。

  • 如果接收者位於不同的處理程序中,則每一個處理程序僅使用單一 Factory。

  • 接收者可以使用同步或非同步作業。假設個別接收者的接收速率中等,則 Complete 要求的用戶端批次處理不會影響接收者輸送量。

  • 讓批次存放區存取保持啟用狀態。如此可降低實體的整體負載。也會降低訊息寫入佇列或主題的整體速率。

  • 將預先擷取計數設定為較小的值 (例如,PrefetchCount = 10)。當其他接收者快取大量訊息時,即可避免接收者發生閒置情況。

目標:將具有少量訂閱之主題的輸送量最大化。許多訂閱會接收一則訊息,這表示所有訂閱的合併接收速率大於傳送速率。傳送者的數目很小。每一訂閱的接收者數目很小。

若要將輸送量最大化,請執行下列動作:

  • 使用磁碟分割主題以改善效能和可用性。

  • 若要提高傳送到主題的整體速率,請使用多個訊息 Factory 來建立傳送者。針對每一個傳送者,使用非同步作業或多個執行緒。

  • 若要提高從訂閱接收的整體速率,請使用多個訊息 Factory 來建立接收者。針對每一個接收者,使用非同步作業或多個執行緒。

  • 使用非同步作業,以便利用用戶端批次處理。

  • 使用預設批次處理間隔 20 毫秒,即可減少 服務匯流排 用戶端通訊協定傳輸數目。

  • 讓批次存放區存取保持啟用狀態。這會提高訊息寫入主題的整體速率。

  • 將預先擷取計數設定為 20 乘以 Factory 之所有接收者的最大處理速率。這會減少 服務匯流排 用戶端通訊協定傳輸數目。

目標:將具有大量訂閱之主題的輸送量最大化。許多訂閱會接收一則訊息,這表示所有訂閱的合併接收速率比傳送速率大許多。傳送者的數目很小。每一訂閱的接收者數目很小。

如果所有訊息都傳送到所有訂閱,則具有大量訂閱的主題通常會顯示很低的整體輸送量。這是因為每一則訊息都接收了許多次,而且主題及其所有訂閱內含的所有訊息都儲存在相同的存放區中。假設每一訂閱的傳送者數目和接收者數目很小。服務匯流排 支援每個主題高達 2,000 筆訂閱。

若要將輸送量最大化,請執行下列動作:

  • 使用磁碟分割主題以改善效能和可用性。

  • 使用非同步作業,以便利用用戶端批次處理。

  • 使用預設批次處理間隔 20 毫秒,即可減少 服務匯流排 用戶端通訊協定傳輸數目。

  • 讓批次存放區存取保持啟用狀態。這會提高訊息寫入主題的整體速率。

  • 將預先擷取計數設定為 20 乘以預計接收速率 (以秒為單位)。這會減少 服務匯流排 用戶端通訊協定傳輸數目。

顯示:
© 2014 Microsoft