脈絡:應用程式需要消費訊息,但它想控制自己何時消費每一則訊息。
輪詢的美妙之處#
訊息消費者存在的理由只有一個——消費訊息。訊息代表待完成的工作,消費者得消費它們並把工作做完。
但消費者怎麼知道有新訊息可用?最容易的作法是反覆檢查通道:有訊息就消費它,然後回頭檢查下一則。這個過程就叫輪詢(polling)。
輪詢的美妙之處在於:消費者是在自己準備好要處理下一則訊息時才去要它——因此它以自己想要的速率消費訊息,而不是以訊息抵達通道的速率。
解法#
它也被稱為同步接收端,因為接收執行緒會阻塞直到收到訊息。之所以叫「輪詢式消費者」,是因為接收端輪詢訊息、處理它、再輪詢下一則。
訊息 API 通常同時提供:
- 一個阻塞到訊息送達的
receive方法 - 以及
receiveNoWait()、Receive(0)這類沒有訊息就立刻返回的方法
Polling Consumer 是應用程式用來明確索取訊息的物件:應用程式準備好要下一則訊息時就去輪詢它,由它從訊息系統取得訊息並回傳。
流程是:應用程式輪詢 → 消費者阻塞直到取得訊息(或滿足其他條件,例如時限)→ 應用程式處理訊息 → 處理完想要下一則就再輪詢。
節流#
使用輪詢式消費者,應用程式能靠限制輪詢執行緒的數量來控制同時消費多少訊息。這能避免接收端被過多請求淹沒——多出來的訊息會排隊等它處理得完。
執行緒配置#
接收端應用程式通常每個想監控的通道至少用一條執行緒,但也可以用單一執行緒監控多個通道,在通道經常是空的時候節省執行緒:
- 輪詢單一通道(且執行緒在訊息抵達前無事可做)→ 用會阻塞的
receive - 用單一執行緒輪詢多個通道,或想在等待時做別的事 → 用帶逾時的
receive或receiveNoWait(),這樣某個通道空的時候,執行緒就能去檢查另一個通道或做別的工作
與其他模式的搭配#
- 多個 Polling Consumer 可以成為 Competing Consumers
- Message Dispatcher 可以實作成 Polling Consumer
- Polling Consumer 可以同時是 Selective Consumer,也可以是 Durable Subscriber
- Polling Consumer 也可以是 Transactional Client,讓消費者能控制訊息何時真正從通道移除
範例:JMS receive 與 .NET Receive
JMS#
MessageConsumer 有三種 receive 方法:
receive()——阻塞直到有訊息可用,然後回傳它receiveNoWait()——檢查一次,回傳訊息或nullreceive(long)——阻塞直到有訊息可用並回傳,或直到逾時並回傳null
Destination dest = // Get the destination
Session session = // Create the session
MessageConsumer consumer = session.createConsumer(dest);
Message message = consumer.receive();.NET#
MessageQueue 客戶端有數種 Receive 變體,最簡單的兩種:
Receive()——阻塞直到有訊息可用,然後回傳它Receive(TimeSpan)——阻塞直到有訊息可用並回傳,或直到逾時並拋出MessageQueueException
MessageQueue queue = // Get the queue
Message message = queue.Receive();