我正在尝试使用春季云流绑定实现自定义的Kafka分区程序。我只想对用户主题进行自定义分区,而对公司主题不做任何事情(在这种情况下,Kafka将使用DefaultPartitioner)。
我的绑定配置:
spring:
cloud:
stream:
bindings:
comp-out:
destination: company
contentType: application/json
user-out:
destination: user
contentType: application/json
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
答案 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
。
鉴于您的问题,我认为您只是将Partitioner
与PartitionSelectorStrategy
弄混了,而您需要后者。
答案 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