我如何同时具有一致的哈希交换和主题交换功能?

时间:2018-12-05 16:00:29

标签: spring-boot hash rabbitmq broker

我有一个水平可扩展的应用程序。我的应用程序是带有2.1.1.RELEASE的spring框架版本的spring-boot服务。

每个工作程序都有一个队列(和它各自的侦听器),并绑定到类型为“ x-consistent-hash”的交换。我使用Rabbitmq版本3.7.7的Rabbitmq-consistent-hash-exchange插件。

根据消息的message_id(as described here)以一致的方式正确地对消息进行哈希处理,并且始终由与我的应用程序相同的工作队列使用这些消息: enter image description here

我实现此目的的代码如下:

public static final String EXCHANGE = "e3";
private static final String EXCHANGE_TYPE = "x-consistent-hash";
@Bean
 public Queue autoDeleteQueue1() {
    return new AnonymousQueue();
    }

    @Qualifier("testlistenerAdapter")
    @Bean
    MessageListenerAdapter testlistenerAdapter(TestListener receiver) {
        MessageListenerAdapter msgadapter = new MessageListenerAdapter(receiver, "testMessageReceived");
        return msgadapter;
    }

    @Qualifier("testcontainer")
    @Bean
    SimpleMessageListenerContainer testcontainer(ConnectionFactory connectionFactory,
            @Qualifier("testlistenerAdapter") MessageListenerAdapter listenerAdapter) throws IOException {

        Connection conn = connectionFactory.createConnection();
        Channel ch = conn.createChannel(true);


        ch.queueDeclare(autoDeleteQueue1().getName(), true, true, true, null);
        ch.queuePurge(autoDeleteQueue1().getName());

        Map<String, Object> args = new HashMap<>();
        args.put("hash-property", "message_id");

        ch.exchangeDeclare(EXCHANGE, EXCHANGE_TYPE, false, false, args);

        ch.queueBind(autoDeleteQueue1().getName(), EXCHANGE, "20");

        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames(autoDeleteQueue1().getName());
        container.setMessageListener(listenerAdapter);
        return container;
    }

我想做的是将所有具有相同message_id的消息路由到与以前相同的工人上,但在不同的队列侦听器上。在第一种情况下,事情很容易,因为一个工人只有一个队列。现在,一个工作人员有多个队列,我希望在同一工作人员中始终对消息进行哈希处理。

我试图通过在每条消息上添加不同的header / routing_key来实现此目的,但是没有成功。

例如,任何带有message_id:“ test”的消息总是路由到同一工作者(让我们说“ worker B”),并且取决于它具有的头文件/ routing_key(foo或bar),foo或bar将使用它。队列侦听器(请参见下图)。我的应用程序的业务逻辑是有状态的,因此我需要具有相同message_id的消息由同一工作人员提供服务。

我尝试了许多实现替代方案,但是似乎这并不是一件容易的事。恐怕我想做的事不可行,因为rabbitmq插件会对队列级别进行哈希处理。一种快速的解决方案是坚持第一种情况。仅保留一种类型的侦听器,然后在同一端点内进行业务逻辑分离。我有什么想法可以实现这种功能,而不必同时合并两个侦听器(foo和bar)的功能?

enter image description here

1 个答案:

答案 0 :(得分:0)

这是行不通的。在rabbitmq中,不同的队列侦听器属于不同的队列。
由于每个工作人员都创建自己的队列,因此我只能保证消息始终在同一队列中,而不是在同一工作人员中。
一致的哈希是在队列级别而不是在工作程序级别进行的。

我通过每个工作人员仅维护一个侦听器队列来完成实现。通过这种方式,我可以确保消息始终在同一工作进程中路由。

如果有人有兴趣看看https://github.com/ubitech/generic-policy-engine-with-consistent-hashing

,我的示例项目就在这里