阅读kafka发送消息文档

This commit is contained in:
asahi
2023-12-28 00:19:39 +08:00
parent 48b5f46d52
commit 308e53cce7

View File

@@ -354,4 +354,104 @@ void updateConfigs(Map<String, Object> updates);
void removeConfig(String configKey); void removeConfig(String configKey);
``` ```
### ReplyingKafkaTemplate
从2.1.3版本开始kafka引入了ReplyingKafkaTemplate其是KafkaTemplate的一个子类用于提供request/reply语义。该类相比父类含有两个额外的方法
```java
RequestReplyFuture<K, V, R> sendAndReceive(ProducerRecord<K, V> record);
RequestReplyFuture<K, V, R> sendAndReceive(ProducerRecord<K, V> record,
Duration replyTimeout);
```
该方法的返回类型RequestReplyFuture继承了CompletableFutureRequestReplyFuture会异步的注入该future的结果可能正常返回也可能是一个exception或者timeout
RequestReplyFuture含有一个sendFuture属性该属性是调用kafkaTemplate的send方法发送消息的结果类型为`CompletableFuture<SendResult<K,V>>`可以通过该属性future来判断发送消息操作的结果。
如果在调用sendAndReceive方法时没有传递replyTimeout参数或是指定replyTimeout参数为null那么该template的`defaultReplyTimeout`属性将会被用作超时时间。默认情况下该超时属性为5s。
从2.8.8版本开始该template还有一个`waitForAssingment`方法。当reply container被配置为`auto.offset.reset=latest`时waitForAssingment方法相当有用避免当reply container尚未初始化完成时发送消息对应的reply已经返回了。
如下展示了如何使用ReplyingKafkaTemplate:
```java
@SpringBootApplication
public class KRequestingApplication {
public static void main(String[] args) {
SpringApplication.run(KRequestingApplication.class, args).close();
}
@Bean
public ApplicationRunner runner(ReplyingKafkaTemplate<String, String, String> template) {
return args -> {
if (!template.waitForAssignment(Duration.ofSeconds(10))) {
throw new IllegalStateException("Reply container did not initialize");
}
ProducerRecord<String, String> record = new ProducerRecord<>("kRequests", "foo");
RequestReplyFuture<String, String, String> replyFuture = template.sendAndReceive(record);
SendResult<String, String> sendResult = replyFuture.getSendFuture().get(10, TimeUnit.SECONDS);
System.out.println("Sent ok: " + sendResult.getRecordMetadata());
ConsumerRecord<String, String> consumerRecord = replyFuture.get(10, TimeUnit.SECONDS);
System.out.println("Return value: " + consumerRecord.value());
};
}
@Bean
public ReplyingKafkaTemplate<String, String, String> replyingTemplate(
ProducerFactory<String, String> pf,
ConcurrentMessageListenerContainer<String, String> repliesContainer) {
return new ReplyingKafkaTemplate<>(pf, repliesContainer);
}
@Bean
public ConcurrentMessageListenerContainer<String, String> repliesContainer(
ConcurrentKafkaListenerContainerFactory<String, String> containerFactory) {
ConcurrentMessageListenerContainer<String, String> repliesContainer =
containerFactory.createContainer("kReplies");
repliesContainer.getContainerProperties().setGroupId("repliesGroup");
repliesContainer.setAutoStartup(false);
return repliesContainer;
}
@Bean
public NewTopic kRequests() {
return TopicBuilder.name("kRequests")
.partitions(10)
.replicas(2)
.build();
}
@Bean
public NewTopic kReplies() {
return TopicBuilder.name("kReplies")
.partitions(10)
.replicas(2)
.build();
}
}
```
在上述示例中采用了spring自动注入的containerFactory来创建reply container。
> #### ErrorHandlingDeserializer
> 可以考虑在reply container中使用ErrorHandlingDeserializer如果反序列化失败RequestReplyFuture将会以异常状态完成可以访问获取到的ExecutionException其cause属性中包含DeserializationException。
### kafka poison pill & ErrorHandlingDeserializer
poison pill在kafka中是指一条被发送到kafka topic中的消息始终被消费失败不管重试过多少次之后仍然无法成功被消费。
poison pill可能在如下场景下产生
- 该记录被损坏
- 该记录发序列化失败
在生产场景中consumer应该配置正确的deserializer来对生产者示例序列化的记录进行反序列化操作。但如果生产者的serializer和消费者的deserializer不兼容将会进入到poison pill的场景。该不兼容情况对key和value的序列化->反序列化场景都有可能发生。
在现实场景中可能因为如下缘故而遭遇poison pill
- 生产者改变了key或value的serializer并且持续向先前的topic中发送消息这将会导致反序列化问题
- consumer的key或value deserializer配置错误
- 不同的生产者实例使用不同的key或value serializer向topic中发送消息
在发生poison后consumer在调用poll拉取数据时将无法反序列化record调用poll时会一直抛出反序列化异常。并且消费者也无法针对posion pill进行处理针对该topic分区的消费会被阻塞因为consumer offset一直无法向前移动。并且在consumer不停重试针对该消息的反序列化时大量的反序列化失败日志将会被追加到日志文件中磁盘占用量将会急剧增大。
#### ErrorHandlingDeserializer
为了解决poison pill问题spring引入了ErrorHandlingDeserializer该deserializer将反序列化工作委托给了一个真实的deserializer。如果底层受托的deserializer反序列化失败那么ErrorHandlingDeserializer将会返回一个null并且在传入的headers中设置DeserializationException对象。DeserializationException对象中包含cause和raw bytes。