如何使用RMQ和Spring云流创建基于分区的使用者

时间:2017-04-27 14:46:18

标签: java spring-cloud-stream spring-rabbitmq

我能够使用cloud stream和rabbit mq开发样本使用者,如果我有3个生成器创建的分区,并且如果我在CF中部署3个实例,则每个实例选择一个队列并使用索引处理消息。

现在的问题是,如果我有10个分区似乎我需要10个实例,这是浪费资源,我们可以让一个消费者监听多个分区。我有基于分区的生产者的原因是因为对我而言,消息序列处理事务。

2 个答案:

答案 0 :(得分:1)

这是一种方式......

@SpringBootApplication
@EnableBinding(TwoInputs.class)
public class So43661064Application {

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

    @StreamListener("input1")
    public void foo1(String in) {
        doFoo(in);
    }

    @StreamListener("input2")
    public void foo2(String in) {
        doFoo(in);
    }

    protected void doFoo(String in) {
        System.out.println(in);
    }

    public interface TwoInputs {

        @Input("input1")
        SubscribableChannel input1();

        @Input("input2")
        SubscribableChannel input2();

    }

}

spring.cloud.stream.bindings.input1.group=bar-0
spring.cloud.stream.bindings.input1.destination=foo
spring.cloud.stream.rabbit.bindings.input1.consumer.bindingRoutingKey=foo-0

spring.cloud.stream.bindings.input2.group=bar-1
spring.cloud.stream.bindings.input2.destination=foo
spring.cloud.stream.rabbit.bindings.input2.consumer.bindingRoutingKey=foo-1

这将消耗answer to your other question中生产者创建的2个分区。

目前还没有办法让@StreamListener直接收听2个分区。

修改

这是另一种方法,使用exchange->exchange绑定...

<强>生产者

@SpringBootApplication
@EnableBinding(Source.class)
public class So43614477Application implements CommandLineRunner {

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

    @Autowired
    private MessageChannel output;

    @Autowired
    private AmqpAdmin admin;

    @Value("${spring.cloud.stream.bindings.output.producer.partition-count}")
    private int partitionCount;

    @Value("${spring.cloud.stream.bindings.output.destination}")
    private String destination;

    @Override
    public void run(String... args) throws Exception {
        for (int i = 0; i < this.partitionCount; i++) {
            String partition = this.destination + "-" + i;
            TopicExchange exchange = new TopicExchange(partition);
            this.admin.declareExchange(exchange);
            Binding binding = BindingBuilder.bind(exchange).to(new TopicExchange(this.destination))
                    .with(partition);
            this.admin.declareBinding(binding);
        }

        output.send(MessageBuilder.withPayload("fiz").setHeader("whichPart", 0).build());
        output.send(MessageBuilder.withPayload("buz").setHeader("whichPart", 1).build());
    }

}

spring.cloud.stream.bindings.output.destination=foo
spring.cloud.stream.bindings.output.producer.partition-key-expression=headers['whichPart']
spring.cloud.stream.bindings.output.producer.partition-count=2

<强>消费

@SpringBootApplication
@EnableBinding(Sink.class)
public class So43661064Application {

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

    @StreamListener(Sink.INPUT)
    public void foo1(String in) {
        System.out.println(in);
    }

}

spring.cloud.stream.bindings.input.group=bar
spring.cloud.stream.bindings.input.destination=foo-0,foo-1

来自主交换机的分区被路由到分区交换机,消费者获得一个交换列表以将其队列绑定到。

您可以在命令行中传递该列表。

答案 1 :(得分:0)

为什么你认为这是浪费资源?如果您的要求规定您需要进行有状态处理,并且您要拆分为多个分区,则N个分区需要N个用户。

如果在同一队列中混合使用不同分区的消息,则您的排序会受到影响。除非您根据某些元数据添加一些逻辑来聚合消息。