最後值佇列是一種特殊的佇列,當新的訊息具有相同的已定義「最後值」屬性值時,會捨棄任何舊的訊息。換句話說,最後值佇列只會保留最後的值。

最後值佇列的典型範例是股票價格,您只對特定股票的最新價格感興趣。

傳送到最後值佇列但沒有指定屬性的訊息將會照常傳送,並且永遠不會被「取代」。

1. 設定

最後值鍵設定

最後值佇列可以在 broker.xml 中透過 last-value-key 靜態設定。

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value-key="reuters_code" />
   </multicast>
</address>

透過使用 CORE API 建立佇列時,將參數 lastValue 設定為 true 即可指定。

或者在使用 JMS Client 時,透過在使用消費者建立目的地時使用位址參數,也可以在自動建立時設定。

Queue queue = session.createQueue("my.destination.name?last-value-key=reuters_code");
Topic topic = session.createTopic("my.destination.name?last-value-key=reuters_code");

可以使用位址萬用字元來設定一組位址的最後值佇列 (請參閱這裡)。

<address-setting match="lastValueQueue">
   <default-last-value-key>reuters_code</default-last-value-key>
</address-setting>

預設情況下,default-last-value-keynull

舊版最後值設定

最後值佇列也可以透過 last-value 布林屬性進行設定,這樣做會將最後值鍵預設為 _AMQ_LVQ_NAME

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value="true" />
   </multicast>
</address>

透過使用 CORE API 建立佇列時,將參數 lastValue 設定為 true 即可指定。

或者在使用 JMS Client 時,透過在使用消費者建立目的地時使用位址參數,也可以在自動建立時設定。

Queue queue = session.createQueue("my.destination.name?last-value=true");
Topic topic = session.createTopic("my.destination.name?last-value=true");

此外,可以使用 address-setting 設定來預設某個位址下的所有佇列。

<address-setting match="lastValueQueue">
   <default-last-value-queue>true</default-last-value-queue>
</address-setting>

預設情況下,default-last-value-queue 為 false。

請注意,address-setting last-value-queue 設定已棄用,請改用 default-last-value-queue

2. 最後值屬性

用於識別最後值的屬性名稱可以在上述的佇列層級設定。

如果使用舊版設定來設定 LVQ,則會使用預設屬性 "_AMQ_LVQ_NAME" (或 Core API 中的常數 Message.HDR_LAST_VALUE_NAME)。

例如,使用範例設定

<address name="foo.bar">
   <multicast>
      <queue name="orders1" last-value-key="reuters_code" />
   </multicast>
</address>

如果兩個具有相同最後值屬性的訊息被傳送到最後值佇列,則只有最新的訊息會保留在佇列中。

// send 1st message with Last-Value property `reuters_code` set to `VOD`
TextMessage message = session.createTextMessage("1st message with Last-Value property set");
message.setStringProperty("reuters_code", "VOD");
producer.send(message);

// send 2nd message with Last-Value property `reuters_code` set to `VOD`
message = session.createTextMessage("2nd message with Last-Value property set");
message.setStringProperty("reuters_code", "VOD");
producer.send(message);

...

// only the 2nd message will be received: it is the latest with
// the Last-Value property set
TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
System.out.format("Received message: %s\n", messageReceived.getText());

3. 強制所有消費者為非破壞性

通常會將最後值佇列與非破壞性語意結合使用。

4. 叢集

最後值佇列和叢集背後的根本概念是互相衝突的。

叢集被設計為透過水平擴展來提高訊息吞吐量的方法。叢集佇列中的訊息可以分散在叢集中的所有節點上。這允許將客戶端分散在整個叢集中,以利用所有節點的運算資源,而不是受限於單一節點。

然而,如果您想在叢集中使用最後值佇列,為了強制執行最後值語意,所有訊息都必須傳送到單一節點上的佇列。這實際上會抵銷叢集的好處。此外,來自其他節點的訊息到達以及從這些節點重新分發訊息到強制執行最後值語意的節點,幾乎肯定會影響哪個訊息被視為「最後」。

基於這些原因,傳統叢集不支援最後值佇列。然而,可以在叢集 (甚至是一組非叢集的 Broker) 前面使用連線路由器,以確保所有需要使用相同最後值佇列的客戶端都被導向到相同的節點。有關設定等的更多詳細資訊,請參閱連線路由器

5. 範例

請參閱最後值佇列範例,其中展示了如何使用 JMS 設定和使用最後值佇列。