spring-cloud-stream-binder-kafka发消息指定 partitionKey

组件版本

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-kafka</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>

背景信息

stream-binder 通过绑定 channel 发送消息很方便,
但 MessageChannel中 send 方法只接收 Message 参数无法指定 partitionKey;

default boolean send(Message<?> message) {
		return send(message, INDEFINITE_TIMEOUT);
}

boolean send(Message<?> message, long timeout);

网友推荐

方法 如下

// 指定
partitionKeyExtractorClass

partitionSelectorClass

partitionKeyExpression

需要自己定义Bean并且 实现对应的接口,略显麻烦。

自查源码

可以在构造 Message 时,设置 header信息 来指定 messageKey,后续会用作选取partition。

// partitionKey 为自定义的 业务key (String类型)
setHeader(KafkaHeaders.MESSAGE_KEY, partitionKey.getBytes())

理论依据

在 KafkaProducerMessageHandler 中 有相应的处理逻辑:

//  org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler.handleRequestMessage(); L348

protected Object handleRequestMessage(final Message<?> message) {
		MessageHeaders messageHeaders = message.getHeaders();
		String topic = this.topicExpression != null ?
				this.topicExpression.getValue(this.evaluationContext, message, String.class)
				: messageHeaders.get(KafkaHeaders.TOPIC, String.class);

		Assert.state(StringUtils.hasText(topic), "The 'topic' can not be empty or null");

		Integer partitionId = this.partitionIdExpression != null ?
				this.partitionIdExpression.getValue(this.evaluationContext, message, Integer.class)
				: messageHeaders.get(KafkaHeaders.PARTITION_ID, Integer.class);

		// 优先级低于 messageKeyExpression
		Object messageKey = this.messageKeyExpression != null
				? this.messageKeyExpression.getValue(this.evaluationContext, message)
				: messageHeaders.get(KafkaHeaders.MESSAGE_KEY);

		Long timestamp = this.timestampExpression != null
				? this.timestampExpression.getValue(this.evaluationContext, message, Long.class)
				: messageHeaders.get(KafkaHeaders.TIMESTAMP, Long.class);
		...
}

DefaultPartitioner 根据 keyBytes 选取 partition

			// org.apache.kafka.clients.producer.internals.DefaultPartitioner.partition L69
			// hash the keyBytes to choose a partition
            return Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值