【问题标题】:How to setup ActiveMQ Artemis redelivery policy not to block the queue如何设置 ActiveMQ Artemis 重新传递策略不阻塞队列
【发布时间】:2019-11-15 01:44:23
【问题描述】:

背景

我在 Apache Artemis 2.7.0.redhat-00056 上有一个 JMS 消息队列。代理配置了 10 分钟的 redelivery-delay。如果我将消息发布到队列并且它在消费者上失败,那么它将作为预定消息返回队列,以在 10 分钟内传递。任何后续发布的消息都会立即处理,因此队列不会被预定消息阻塞。

如果连续快速发送多条消息,那么它们都会失败并被安排为 10 分钟的时间。在这种情况下,Artemis 似乎正在尝试保留消息顺序。

文档

关于重新投递的文档是这样说的:

其他后续消息会定时发送,只有取消的消息会在延迟后异步发送回队列。

Redelivery documentation

问题

在我看来,如果您连续发布消息,Artemis 似乎会保留顺序,而如果消息之间有轻微延迟,则队列不会阻塞,只有失败的消息会延迟调度(根据文档)。

我正在尝试找到一种解决方案,以便在一条消息失败并且需要在 10 分钟内重新发送时,它不会阻止后续消息。

示例

重新创建它不需要任何特殊的东西。如前所述,您只需将一些消息快速连续发送到在代理上具有重新传递策略的队列。我一直在测试一个基本示例,如下所示:

在启动时产生五条消息的 Spring Boot 应用程序。

@SpringBootApplication
public class ArtemisTestApplication
{

    private Logger logger = LoggerFactory.getLogger(ArtemisTestApplication.class);

    @Autowired
    private JmsTemplate jmsTemplate;

    @PostConstruct
    public void init()
    {
        send("Message1");
        send("Message2");
        send("Message3");
        send("Message4");
        send("Message5");
    }

    public void send(String msg)
    {
        logger.debug("Sending message :{}", msg);
        jmsTemplate.convertAndSend("jms.queue.TestQueue", msg);
    }

    public static void main(String[] args)
    {
        SpringApplication.run(ArtemisTestApplication.class, args);
    }

}

消费消息并引发错误以触发重新投递政策。

@Component
public class TestConsumer
{
    private Logger logger = LoggerFactory.getLogger(TestConsumer.class);

    @JmsListener(destination = "jms.queue.TestQueue")
    public void receive(TextMessage message) throws JMSException
    {
        logger.debug("Message received: {}", message.getText());
        throw new RuntimeException("Force redelivery policy");
    }
}

该应用是使用spring boot initializr 生成的。除了给它一个名字之外,唯一需要注意的是消息传递下的 artemis 依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-artemis</artifactId>
    </dependency>

在 application.properties 中,我已将连接属性配置到本地运行的 Artemis 实例。

spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=
spring.artemis.password=

在代理上,我为队列配置了重新投递策略。注意:我这里将延迟设置为 0,问题仍然存在,因为所有消息都被阻止,直到第一条消息尝试了 3 次并被移动到 DLQ。如果您将延迟更改为正数,那么您会看到所有五封邮件都安排在稍后发送。

<address-settings>      
    <address-setting match="jms.queue.TestQueue">            
        <dead-letter-address>DLQ</dead-letter-address>                      
        <redelivery-delay>0</redelivery-delay>    
        <max-delivery-attempts>3</max-delivery-attempts>
    </address-setting>    
  </address-settings>

<addresses>     
    <address name="DLQ">            
        <anycast>               
          <queue name="DLQ" />            
        </anycast>         
      </address>       
      <address name="jms.queue.TestQueue">            
        <anycast>               
          <queue name="jms.queue.TestQueue" />            
        </anycast>         
      </address>                      
</addresses>

【问题讨论】:

  • 您能否为此提供minimal, reproducible example?
  • 另外,你说,“在这种情况下,Artemis 试图保持消息顺序。”您提出这种说法的依据是什么?
  • 在我昨天阅读的各种文章中,我发现了一些内容,即 Artemis 将尝试保留同一生产者发送的消息的顺序。除了这是轶事之外,我可以使用 listScheduledMessages 操作查看消息组,并且它们都安排在 10 分钟后,但是,实际上只有第一个被传递,并且当后续消息最终传递时,传递计数为 1。所以它的行为肯定就像它在保持顺序一样。
  • 我已按要求添加了一个示例,尽管我认为它在这里没有多大帮助。代码没有什么特别之处,它是最基本的示例,即快速连续添加一些消息,然后通过重新传递策略使用它们。这是关于队列如何工作而不是我的代码的问题。
  • Artemis 将尝试保留同一生产者发送的消息的顺序,因为这是 JMS 规范所期望的。但是,诸如集群中消息的重新分配或负载平衡或重新传递延迟之类的事情最终可能会改变顺序。 JMS 规范没有解决所有这些情况。

标签: jms spring-jms activemq-artemis


【解决方案1】:

我得出的结论是,这是 Artemis 的一个错误。我为此提出了一张票,并留下了其他人遇到同样问题的评论。

https://issues.apache.org/jira/browse/ARTEMIS-2417

与此同时,我不得不更改我们的客户端应用程序来处理重新投递政策本身。如果读取消息时出现错误,那么我们会在消息上增加一个计数器,并将其作为具有所需延迟的新消息写入。然后确认正在消费的消息以解除阻塞队列并允许读取其他消息。我已将代理上配置的重新交付策略保留为备用,以防出现此逻辑之外的错误或未捕获的错误。这并不理想,但至少现在可以满足要求。

【讨论】:

  • 如 JIRA 中所述,当前的解决方法是在客户端的 URL 上设置 consumerWindowSize=0。
猜你喜欢
  • 1970-01-01
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-31
  • 2018-04-23
  • 1970-01-01
  • 2021-07-22
相关资源
最近更新 更多