最后值队列是一种特殊的队列,当队列中放入具有相同最后值属性的新消息时,它会丢弃任何消息。换句话说,最后值队列只保留最后一个值。
最后值队列的一个典型例子是股票价格,您只关心特定股票的最新值。
发送到最后值队列而不指定属性的消息将像往常一样传递,并且永远不会被“替换”。
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 客户端时,在创建消费者使用的目标时使用地址参数进行自动创建。
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-key
为 null
。
传统最后值配置
最后值队列也可以通过 last-value
布尔属性配置,这样做会将 last-value-key 默认设置为 _AMQ_LVQ_NAME
。
<address name="foo.bar">
<multicast>
<queue name="orders1" last-value="true" />
</multicast>
</address>
在使用 CORE api 创建队列时指定,将参数 lastValue
设置为 true
。
或者,在使用 JMS 客户端时,在创建消费者使用的目标时使用地址参数进行自动创建。
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. 集群
最后值队列和集群背后的基本理念相互矛盾。
集群被设计为通过水平扩展来提高消息吞吐量。集群队列中的消息可以分布在集群中的所有节点上。这允许客户端分布在整个集群中,以利用所有节点的计算资源,而不是被单个节点瓶颈。
但是,如果您想在集群中使用最后值队列,那么为了强制执行最后值语义,所有消息都需要发送到单个节点上的队列。这将有效地抵消集群的好处。此外,到达其他节点的消息以及从其他节点重新分配的消息(而不是强制执行最后值语义的节点)几乎肯定会影响哪个消息被认为是“最后一个”。