Pusar key_share消费模式指定key消费数据

参考文章技术探究|深入解析 Apache Pulsar Key_Shared 订阅模式原理与最佳实践 - StreamNative - OSCHINA - 中文开源技术交流社区

pulsar的主题订阅模式包括四种:独占(exclusive)、共享(shared)、灾备(failover)、key共享(key_shared)。

独占:一个订阅只与一个消费者可以关联,只有这个消费者接收到topic的全部消息,如果这个消费者故障了就会停止消费。

灾备:一个订阅可以与多个消费者关联,但只有一个消费者会消费到数据,当该消费者故障时,由另一个消费者来继续消费。

共享:一个订阅可以与多个消费者关联,消息通过轮询机制发送给不同的消费者。YPulsar默认使用共享模式。

key共享:一个订阅可以与多个消费者关联,消息根据给定的映射规则,相同key的消息由同一个消费者消费。

在key_share消费模式中, 先启动consume1,再启动consume2。consume1和consume2都是active consume。相同key的消息只能被一个consume消费,但一个key被哪个consume消费是随机的。

Broker 内部的 Dispatcher 组件负责消费的消息分发和流量控制。Pulsar 支持的 4 种订阅模式也是通过 Dispatcher 来控制的,其中 Key_Shared 模式下 Dispatcher 重要的功能是把相同 Key 的消息分配给相同的 Consumer,从而保证相同 Key 的消息有序。

将 Key 进行哈希后得到一个 HashCode,再将 HashCode 映射到一个指定范围 Key Range,然后 Dispatcher 根据 Key Range 对消息进行分配。

Dispatcher 首先获取消息的 OrderingKey。如果 OrderingKey 为空,再尝试获取设置的 Key 字段进行 Hash 运算,默认使用 MurmurHash 算法计算出 HashCode,具体方法如下:

public int makeHash(byte[] b) {
   return org.apache.pulsar.common.util.Murmur3_32Hash.getInstance().makeHash(b) & Integer.MAX_VALUE;
}

由此,我们可以在消费端配置消费的HashCode范围来限定消费端消费的消息

例如,生产端发送消息:

//创建生产者
Producer producer = client
    .newProducer(Schema.STRING)
    .producerName("name")
    .topic(topic)
//是否开启批量处理消息,默认true,需要注意的是enableBatching只在异步发送sendAsync生效,同步发送send失效。因此建议生产环境若想使用批处理,则需使用异步发送,或者多线程同步发送
    .enableBatching(true)
//消息压缩(四种压缩方式:LZ4,ZLIB,ZSTD,SNAPPY),consumer端不用做改动就能消费,开启后大约可以降低3/4带宽消耗和存储(官方测试)
    .compressionType(CompressionType.SNAPPY)
//批量发送不适合key_share模式,会按照这一批数据的第一条key作为整批数据的key,可以将上面的enableBatching设置为false关闭批量发送,或者采用BatcherBuilder.KEY_BASED方式将同样的key作为一批发送
    .batcherBuilder(BatcherBuilder.KEY_BASED)
    .create();
//下面是模拟的业务数据
Random ran1 = new Random();
String str =ran1.nextInt(300) + "," + ran1.nextInt(300) + "," + ran1.nextInt(300) + "," + "2320.0, 2321.0, 2097.0, 2040.0]";
//分别为数据添加两种key发送
for (int i = 1; i < 2000000000; i++) {
    if (i%2 ==0){
       producer.newMessage()
            .key("dataStream")
            .value(str)
            .send();
       Thread.sleep(5000);
    }else {
       producer.newMessage()
            .key("stateStream")
            .value(str)
            .send();
       Thread.sleep(5000);
   }
}

计算key:dataStream和stateStream的HashCode值

String data = "dataStream";
String state = "stateStream";
final int d = Murmur3_32Hash.getInstance().makeHash(data.getBytes()) % 65536;
final int s = Murmur3_32Hash.getInstance().makeHash(state.getBytes()) % 65536;
System.out.println("datakey: "+ d);
System.out.println("statekey: "+ s);

计算的结果是:
datakey: 59815
statekey: 3473

消费端代码:

ArrayList ranges = new ArrayList<>();
ranges.add(Range.of(59815,59815));
Consumer consumer = client.newConsumer(Schema.STRING)
       .topic(topic)
       .subscriptionName("fixed-key-share-test")
       .consumerName("data")
//指定消费方式为Key_share
       .subscriptionType(SubscriptionType.Key_Shared)
//指定range消费范围,传入值为key:dataStream经过计算后的HashCode值,范围是[a,b),可以传入多个范围
       .keySharedPolicy(KeySharedPolicy
            .stickyHashRange()
            .ranges(ranges))
       .subscribe();
int i = 1;
//接收数据
while (true) {
     Messages receive = consumer.batchReceive();
     for (Message message : receive) {
        final String value = message.getValue();
        final String key = message.getKey();
        System.out.println("第" + i + "条消息: " + value +" key: "+key);
        consumer.acknowledge(message);
        i++;
    }
}

消费结果

第1条消息: 16,62,100,2320.0, 2321.0, 2097.0, 2040.0] time: 32 key: dataStream
第2条消息: 42,88,46,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第3条消息: 93,208,130,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第4条消息: 288,122,256,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第5条消息: 60,40,77,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第6条消息: 179,84,64,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第7条消息: 138,148,19,2320.0, 2321.0, 2097.0, 2040.0] time: 33 key: dataStream
第8条消息: 205,150,266,2320.0, 2321.0, 2097.0, 2040.0] time: 35 key: dataStream
第9条消息: 163,132,39,2320.0, 2321.0, 2097.0, 2040.0] time: 37 key: dataStream

消费端只消费了key为dataStream的数据

你可能感兴趣的:(java,开发语言)