1 故障背景
10:09:34.948 ifpo.apache .kafka.clients .Networkclient 748[Producer clientId=producer-1] Connection to node 0(10.x.x.x:9093) could not be established. Broker may not be available.
故障细节
生产kafka 服务端集群全部宕机,但车端还在往我的数据网关服务上报信息,而此时生产 kafka 集群全部宕机,但是这种异常,网关服务不会走到send 语句的 catch 语句块,因为这只是warn 而非 error 日志。所以导致这些数据全部丢失,直至发现大屏数据缺失!垃圾百度云的机器宕机且无任何告警!
解决方案
- 百度云运维给出平台控制台的监控告警方案
- 对 kafka broker 端探活自动重启
- kakfa 生产者客户端,考虑 fail fast方案,由数据网关这个 Java 生产者客户端代码实现,当 kafka 服务端宕机时,使发送消息 API 报错并让 java 客户端服务宕机。
环境
kafka 2.5.1 版本-百度云BMR集群。
2 客户端捕获异常
若希望在Kafka服务端宕机时让Java客户端抛出异常并且让服务宕机,可设置一些Kafka生产者参数实现。
可设:
- retries
- delivery.timeout.ms
控制生产者在放弃之前可以重试发送消息的次数和总时间。
默认情况下,Kafka生产者可能会重试多次发送消息,如果Kafka服务端宕机,生产者将会尝试在delivery.timeout.ms
设置的时间内重试,直到超时。如果在这段时间内服务没有恢复,生产者将抛出一个TimeoutException
,这时候你的服务可以捕获这个异常并作出相应的处理,比如让服务宕机。
以下是一个设置重试和超时参数的示例:
Properties props = new Properties();
props.put("bootstrap.servers", "your_kafka_broker:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");
props.put("retries", 0); // 设置重试次数为0,表示不重试
props.put("delivery.timeout.ms", 15000); // 设置消息发送超时时间
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
在这个例子中,如果Kafka服务端宕机,生产者在发送消息时会立即失败而不进行重试,并且会在15秒后超时。这样,send
方法会抛出一个TimeoutException
。
然后,在你的send
方法中,你可以捕获这个异常,并采取措施比如停止服务:
public void send(String topic, String key, String msg){
try {
producer.send(new ProducerRecord<>(topic, key, msg)).get();
} catch (InterruptedException | ExecutionException e) {
log.error("kafka send error: {}", e.getMessage(), e);
// 在这里处理异常,比如让服务宕机
System.exit(1); // 非零状态码表示异常退出
}
}
生产环境直接System.exit(1)
会突然停止服务,而非优雅关闭。
实际应用可能想要实现一些更优雅的关闭过程,如关闭资源、通知依赖服务、等待正在处理的任务完成等。此外,你应确保这样的异常处理逻辑符合你的服务的容错和高可用策略。