在Apache Kafka中,生产者发送消息有两种模式:同步发送(Synchronous Send)和异步发送(Asynchronous Send)。这两种模式的区别主要在于消息发送后的处理方式以及对消息确认的即时性要求。
同步发送(Synchronous Send):
同步发送意味着生产者在发送消息后会立即阻塞,等待Kafka Broker返回确认响应。只有当Broker确认消息已经写入指定分区且复制到满足副本因子的节点上时(达到指定的acks
配置),生产者才会解除阻塞并继续执行后续操作。这种方式提供了最高的数据可靠性,确保消息在发送后已经被Kafka集群接收并持久化。
以下是同步发送的示例代码:
import org.apache.kafka.clients.producer.RecordMetadata;
// ...
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key", "value");
try {
RecordMetadata metadata = producer.send(record).get(); // 同步发送并等待结果
System.out.printf("Produced record to topic '%s' partition [%d] @ offset %d%n",
metadata.topic(), metadata.partition(), metadata.offset());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); // 处理发送异常
}
异步发送(Asynchronous Send):
异步发送则允许生产者在发送消息后立即返回,不等待Broker的确认响应。生产者通过传递一个回调函数(Callback
接口的实现)给send()
方法,该回调函数将在消息发送结果(成功或失败)可用时被异步调用。这种模式提高了生产者的发送效率,因为它无需等待每个消息的确认即可继续发送下一条消息,适用于对吞吐量要求较高的场景。但请注意,由于异步发送不会立即得知消息是否成功写入Kafka,因此在处理异常和保证消息可靠性方面需要额外关注。
下面是异步发送的示例代码,与前面给出的示例类似,只是使用了回调函数:
import org.apache.kafka.clients.producer.RecordMetadata;
// ...
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key", "value");
producer.send(record, (metadata, exception) -> {
if (exception != null) {
exception.printStackTrace(); // 处理发送异常
} else {
System.out.printf("Produced record to topic '%s' partition [%d] @ offset %d%n",
metadata.topic(), metadata.partition(), metadata.offset());
}
});
选择同步还是异步发送:
选择哪种发送方式取决于应用程序的具体需求:
-
如果需要最高级别的消息可靠性,且对发送延迟不敏感,可以选择同步发送。这种方式确保每条消息发送后都能立即得到Broker的确认,一旦出现异常,生产者能立即感知并采取相应措施。
-
如果追求高吞吐量,且可以接受一定程度的消息丢失风险或通过其他机制(如重试、幂等处理等)来保证最终一致性,可以选择异步发送。这种方式能够显著提高消息发送速率,但需要在回调函数中妥善处理发送失败的情况。
在实际使用中,可以根据业务场景的特性和对消息传递服务质量的要求,灵活选择同步或异步发送模式,甚至在同一应用中结合使用两种模式,以适应不同的消息发送需求。