Apache ActiveMQ Artemis 包含强大的自动重复消息检测功能,无需您在应用程序级别编写自己的繁琐的重复检测逻辑,即可过滤掉重复消息。本章将解释什么是重复检测,Apache ActiveMQ Artemis 如何使用它以及如何在何处配置它。

当从客户端向服务器发送消息,或者从一台服务器向另一台服务器发送消息时,如果目标服务器或连接在发送消息后但发送方收到响应(表明发送或提交已成功处理)之前失败,则发送方无法确定消息是否已成功发送到地址。

如果目标服务器或连接在收到并处理发送后但响应发送回之前失败,则消息将已成功发送到地址。但是,如果目标服务器或连接在收到并完成处理发送之前失败,则消息将不会成功发送到地址。从发送方的角度来看,无法区分这两种情况。

当服务器恢复时,这会让客户端陷入困境。它知道目标服务器已失败,但不知道最后一条消息是否已成功到达目的地。如果它决定重新发送最后一条消息,则可能会导致重复消息被发送到地址。如果每条消息都是一个订单或一笔交易,则这会导致订单被执行两次或交易被重复预订。这显然不是一个理想的情况。

在事务中发送消息(s)也无济于事。如果服务器或连接在事务提交正在处理时失败,则同样无法确定事务是否已成功提交!

为了解决这些问题,Apache ActiveMQ Artemis 为发送到地址的消息提供了自动重复消息检测功能。

1. 使用重复检测发送消息

为发送的消息启用重复消息检测很简单:您只需要在消息上设置一个特殊属性为唯一值。您可以根据需要创建该值,只要它是唯一的即可。当目标服务器收到消息时,它将检查是否已设置该属性,如果已设置,则它将在其内存缓存中检查是否已收到具有该标头值的相同消息。如果之前已收到具有相同值的相同消息,则它将忽略该消息。

使用重复检测在节点之间移动消息可以为您提供与使用 XA 事务从源读取消息并将其发送到目标时相同的*一次且仅一次*传递保证,但开销更低,配置也比使用 XA 容易得多。

如果您在事务中发送消息,则不必为事务中发送的*每条*消息设置该属性,您只需要在事务中设置一次即可。如果服务器在事务中的任何消息中检测到重复消息,则它将忽略整个事务。

您设置的属性名称由org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID的值给出,该值为_AMQ_DUPL_ID

如果您使用的是核心 API,则该属性的值可以是byte[]SimpleString类型。如果您使用的是 JMS,它必须是String,并且它的值应该是唯一的。生成唯一 ID 的一种简单方法是生成 UUID。

以下是使用核心 API 设置该属性的示例

...

ClientMessage message = session.createMessage(true);

SimpleString myUniqueID = "This is my unique id";   // Could use a UUID for this

message.setStringProperty(HDR_DUPLICATE_DETECTION_ID, myUniqueID);

以下是使用 JMS API 的示例

...

Message jmsMessage = session.createMessage();

String myUniqueID = "This is my unique id";   // Could use a UUID for this

message.setStringProperty(HDR_DUPLICATE_DETECTION_ID.toString(), myUniqueID);

...

2. 配置重复 ID 缓存

服务器维护发送到每个地址的org.apache.activemq.artemis.core.message.impl.HDR_DUPLICATE_DETECTION_ID属性已接收值的缓存。每个地址都有自己独立的缓存。

缓存是循环固定大小缓存。如果缓存的最大大小为n个元素,则存储的第n + 1个 ID 将覆盖缓存中的第0个元素。

缓存的最大大小由broker.xml中的参数id-cache-size配置,默认值为20000个元素。

要实现地址特定的id-cache-size,可以在broker.xml中相应地址设置部分添加。为特定地址指定所需的id-cache-size值。当消息发送到配置了特定id-cache-size的地址时,它将优先于全局id-cache-size值,从而为重复 ID 缓存提供更大的灵活性和优化。

缓存也可以配置为持久化到磁盘或不持久化。这由参数persist-id-cache配置,也位于broker.xml中。如果将其设置为true,则每个 ID 在接收时都会持久化到永久存储。此参数的默认值为true

在选择重复 ID 缓存的大小之前,请确保将其设置为足够大的大小,以便如果您重新发送消息,所有先前发送的消息都位于缓存中,而不会被覆盖。

3. 重复检测和桥接

核心桥接可以配置为在将消息转发到其目标之前自动添加唯一重复 ID 值(如果消息中没有)。这确保如果目标服务器崩溃或连接中断,并且桥接重新发送消息,则如果目标服务器已经接收了消息,它将被忽略。

要将核心桥接配置为添加重复 ID 标头,只需在broker.xml中配置桥接时将use-duplicate-detection设置为true

此参数的默认值为true

有关核心桥接以及如何配置它们的更多信息,请参阅核心桥接.

4. 重复检测和集群连接

集群连接在内部使用核心桥接将消息可靠地在集群的节点之间移动。因此,它们也可以配置为使用其内部桥接为其移动的每条消息插入重复 ID 标头。

要将集群连接配置为添加重复 ID 标头,只需在broker.xml中配置集群连接时将use-duplicate-detection设置为true

此参数的默认值为true

有关集群连接以及如何配置它们的更多信息,请参阅集群.