关于springcloud kafka binder的一个关于consumer group设置的一个bug

来源:互联网 发布:鹏为crm软件 编辑:程序博客网 时间:2024/05/18 19:43

我们可以通过spring.cloud.stream.kafka.bindings.springCloudBusInput.consumer.group来指定默认总线topic:spingCloudBus的consumer group,比如设置成${spring.application.name}:${spring.application.index},这样我们在kafka manager界面上可以方便的识别出某个服务的offset消费情况。

默认情况下group是一个随机值,在KafkaMessageChannelBinder类的createConsumerEndpoint开头代码:

boolean anonymous = !StringUtils.hasText(group);Assert.isTrue(!anonymous || !extendedConsumerProperties.getExtension().isEnableDlq(),"DLQ support is not available for anonymous subscriptions");String consumerGroup = anonymous ? "anonymous." + UUID.randomUUID().toString() : group;

意思是如果设置了group的话,那么就用设置的,否则将生成一个类似anonymous.fc5eeeac-d7af-44dc-8973-76517484013a这样的group id。

该类中另外一个方法:

private ConsumerFactory<?, ?> createKafkaConsumerFactory(boolean anonymous, String consumerGroup,ExtendedConsumerProperties<KafkaConsumerProperties> consumerProperties) {Map<String, Object> props = new HashMap<>();props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 100);if (!ObjectUtils.isEmpty(configurationProperties.getConfiguration())) {props.putAll(configurationProperties.getConfiguration());}if (ObjectUtils.isEmpty(props.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG))) {props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.configurationProperties.getKafkaConnectionString());}if (!ObjectUtils.isEmpty(consumerProperties.getExtension().getConfiguration())) {props.putAll(consumerProperties.getExtension().getConfiguration());}props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroup);props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, anonymous ? "latest" : "earliest");return new DefaultKafkaConsumerFactory<>(props);}
将通过是否是anonymous来设置auto.offset.reset是从latest还是earliest开始消费,即一个新的group将从最开始还是从最新offset开始消费。

这样如果你设置了group,那么将会从earliest开始消费,那么原来这个topic上的消息将会重新被消费一遍。

这就导致如果我们想从latest开始消费,就不能够定制group name了。该BUG出现在目前最新的GA版本(Dalston.SR3),对应的spring-cloud-stream-binder-kafka是1.2.1版本,1.2.1以上版本修复了这个问题:https://github.com/spring-cloud/spring-cloud-stream-binder-kafka/commit/7355ada4613ad50fe95430f1859d4ea65f004be1#diff-b0b05f37655e15c59cb8dfee2cc5353d

:

private ConsumerFactory<?, ?> createKafkaConsumerFactory(boolean anonymous, String consumerGroup, ExtendedConsumerProperties<KafkaConsumerProperties> consumerProperties) { Map<String, Object> props = new HashMap<>(); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);  props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);  props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);  props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 100); +props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, anonymous ? "latest" : "earliest"); +  if (!ObjectUtils.isEmpty(configurationProperties.getConfiguration())) {  props.putAll(configurationProperties.getConfiguration());  } if (ObjectUtils.isEmpty(props.get(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG))) { props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.configurationProperties.getKafkaConnectionString()); }  if (!ObjectUtils.isEmpty(consumerProperties.getExtension().getConfiguration())) {  props.putAll(consumerProperties.getExtension().getConfiguration());  } +  props.put(ConsumerConfig.GROUP_ID_CONFIG, consumerGroup); -props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, anonymous ? "latest" : "earliest"); +if (!ObjectUtils.isEmpty(consumerProperties.getExtension().getStartOffset())) { +props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, consumerProperties.getExtension().getStartOffset().name()); +} +  return new DefaultKafkaConsumerFactory<>(props);  }
如果有设置startOffset属性的话,将根据该属性重新赋值,这样我们就可以改变group名称,然后将spring.cloud.stream.kafka.bindings.springCloudBusInput.consumer.startOffset=latest来设置从最新开始消费。


另外http://cloud.spring.io/spring-cloud-static/Dalston.SR3/#_configuration_options_2的官方文档上的描述其实跟实际代码内容不符,估计是patch忘记打上去了:

resetOffsets

Whether to reset offsets on the consumer to the value provided by startOffset.

Default: false.

startOffset

The starting offset for new groups, or when resetOffsets is true. Allowed values: earliest, latest. If the consumer group is set explicitly for the consumer 'binding' (via spring.cloud.stream.bindings.<channelName>.group), then 'startOffset' is set to earliest; otherwise it is set to latest for the anonymousconsumer group.

Default: null (equivalent to earliest).

Dalston.SR3版本的文档上已经标注了这个属性,上面那个resetOffsets好像没用到,也与文档描述不符,直接设置startOffset就好了。