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

我们可以通过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 consumerProperties) {
		Map 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 consumerProperties) {
 		Map 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..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就好了。

















你可能感兴趣的:(spring,cloud)