如何使用Spring Cloud Stream实现自定义Kafka分区

时间:2019-06-19 21:05:53

标签: java apache-kafka partitioning spring-cloud-stream

我正在尝试使用春季云流绑定实现自定义的Kafka分区程序。我只想对用户主题进行自定义分区,而对公司主题不做任何事情(在这种情况下,Kafka将使用DefaultPartitioner)。

我的绑定配置:

spring:
  cloud:
    stream:
      bindings:
        comp-out:
          destination: company
          contentType: application/json
        user-out:
          destination: user
          contentType: application/json

根据参考文件:https://cloud.spring.io/spring-cloud-static/spring-cloud-stream-binder-kafka/2.1.0.RC4/single/spring-cloud-stream-binder-kafka.html#_partitioning_with_the_kafka_binder 我将配置修改为此:

spring:
  cloud:
    stream:
      bindings:
        comp-out:
          destination: company
          contentType: application/json
        user-out:
          destination: user
          contentType: application/json
		      producer:
            partitioned: true
            partitionSelectorClass: config.UserPartitioner

我使用以下方法将消息发布到流中:

public void postUserStream(User user) throws ServiceException {
        try {
            LOG.info("Posting User {} into Kafka stream...", user);
            MessageChannel messageChannel = messageStreams.outboundUser();
            messageChannel
                    .send(MessageBuilder.withPayload(user)
                            .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build());
        } catch (Exception ex) {
            LOG.error("Error while populating User stream into Kafka.. ", ex);
            throw ex;
        }
    }

我的UserPartitioner类:

public class UserPartitioner extends DefaultPartitioner {
    @Override
    public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes,
          Cluster cluster) {

        String partitionKey = null;
        if (Objects.nonNull(value)) {
            User user = (User) value;
            partitionKey = String.valueOf(user.getCompanyId()) + "_" + String.valueOf(user.getId());
            keyBytes = partitionKey.getBytes();
        }
        return super.partition(topic, partitionKey, keyBytes, value, valueBytes, cluster);
    }
}

我最终收到以下异常:

说明: 无法将“ spring.cloud.stream.bindings.user-out.producer”下的属性绑定到org.springframework.cloud.stream.binder.ProducerProperties:

Property: spring.cloud.stream.bindings.user-out.producer.partitioned
Value: true
Origin: "spring.cloud.stream.bindings.user-out.producer.partitioned" from property source "bootstrapProperties"
Reason: No setter found for property: partitioned

操作: 更新您的应用程序的配置

有关如何使用消息绑定器设置“自定义分区”的任何参考链接都将很有帮助。

编辑:基于文档,也尝试了以下步骤:

用户退出:           目的地:用户           contentType:application / json           生产者:            partitionKeyExtractorClass:config.SimpleUserPartitioner

@Component
public class SimpleUserPartitioner implements PartitionKeyExtractorStrategy {

	@Override
	public Object extractKey(Message<?> message) {
		if(message.getPayload() instanceof BaseUser) {
			BaseUser user = (BaseUser) message.getPayload();
			return user.getId();
		}
		return 10;
	}
    
}

更新2:对我有用的解决方案在活页夹中将partitioncount添加到绑定,将autoaddpartitions添加到true:

spring:
  logging:
    level: info
  cloud:
    stream:
      bindings:
        user-out:
          destination: user
          contentType: application/json
          producer:
            partition-key-expression: headers['partitionKey']
            partition-count: 4

spring:
  cloud:
    stream:
      kafka:
        binder:
          brokers: localhost:9092
          autoAddPartitions: true

2 个答案:

答案 0 :(得分:1)

没有属性partitioned;吸气剂取决于其他属性...

public boolean isPartitioned() {
    return this.partitionKeyExpression != null
            || this.partitionKeyExtractorName != null;
}

partitionSelectorClass: config.UserPartitioner

UserPartitioner是Kafka Partitioner-它确定哪些使用者(在使用者方面)获得哪个分区

partitionSelectorClass必须是PartitionSelectorStrategy-它确定记录被发送到(在生产者端)的哪个分区。

这些是完全不同的对象。

如果您真的想要自定义分区在消费者实例之间分布的方式,那就是Kafka关心的问题,与Spring无关。

此外,同一活页夹中的所有使用者绑定都将使用相同的Partitioner。您必须将多个活页夹配置为具有不同的Partitioner

鉴于您的问题,我认为您只是将PartitionerPartitionSelectorStrategy弄混了,而您需要后者。

答案 1 :(得分:0)

另外,请注意; partitionSelectorClass。已被弃用一段时间,并已在当前主版本中删除(在3.0.0中不可用),以partitionSelectorName-https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/3.0.0.M1/spring-cloud-stream.html#spring-cloud-stream-overview-partitioning

代替