kafka消息可靠性

                                          kafka消息可靠性

轉載:kafka消息可靠性

發送可靠性

kafka新版client(0.10.x)使用java重新實現。使用的是異步方式發送消息,即消息提交給KafkaProducer的send方法後,實際上是將該消息放入了它本身的一個後臺發送隊列,然後再有一個後臺線程不斷地從隊列中取出消息進行發送,發送成功後會回調send方法的callback(如果沒有,就不用回調了)。

從以上的流程來看,kafka客戶端的發送流程是一個異步化的流程,kafka客戶端會累積一定量的消息後統一組裝成一個批量消息發出,這個的觸發條件是: 消息量達到了batch.size的大小或者等待批量的時間超過了linger.ms時間。

此外還要注意一下發送方消息的堆積問題,當程序的發送速率大於發送到broker的速率時,會產生消費在發送方堆積,堆積的策略控制主要由參數buffer.memory 以及max.block.ms。buffer.memory設置了可使用的buffer內存,max.block.ms是指在buffer滿的情況下可以阻塞多長時間,超過這個時間則拋出異常。

消息失敗重試

設置失敗重試的次數爲一個很大的數值,如Integer.MAX_VALUE,對應properties的設置爲:

配置 默認值 建議值
retries 0 Integer.MAX_VALUE

消息異步轉同步

對於消息異步轉同步:使用future.get()等待消息發送返回結果,如:

Future<RecordMetadata> future = producer.send(new ProducerRecord<String, String>("test.testTopic", "key","value"));
RecordMetadata metadata = future.get(); //等待發送結果返回
 

 

這種用法可能會導致性能下降比較厲害,也可以通過send(message,callback)的方式,在消息發送失敗時通過callback記錄失敗並處理

順序消息

kafka默認情況下是批量發送,批量發送存在消息積累再發送的過程,爲了達到消息send後立刻發送到broker的要求,對應properties設置:

配置 默認值 建議值
max.in.flight.requests.per.connection 5 1

其中max.in.flight.requests.per.connection以及retries主要應用於順序消息場景,順序場景中需要設置爲:
max.in.flight.requests.per.connection = 1

綜合以上配置示例:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "1"); //這裏是只要求leader響應就OK,更高的要求則應該設置成"all"
props.put("retries", Integer.MAX_VALUE);
props.put("max.in.flight.requests.per.connection",1);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); //這裏是key的序列化類
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");//這裏是value的序列化類

Producer<String, String> producer = new KafkaProducer<String,String>(props);
for (int i = 0; i < 1000000; i++) {
   Future<RecordMetadata> future = producer.send(new ProducerRecord<String, String>("test.testTopic","key","value"));
   RecordMetadata metadata = future.get(); //關鍵的這一步,同步等待發送完成
}
producer.close();
 

 

接收可靠性

新版的java客戶端(0.10.0.0)已經變更接收線程爲單線程接收處理。
同時客戶端默認情況下是自動提交offset,這樣可能存在消息丟失的可能性,比如客戶端接收到一批消息並進行處理,在處理過程中達到了客戶端offset定時提交的時間點,這批數據的offset被提交,但是可能這批數據的處理還沒有結束,甚至這些數據可能還存在一些數據處理不了或者處理出錯,甚至出現宕機的可能性,這時未處理的消息將會丟失,因爲offset已經提交,下次讀取會從新的offset處讀取。所以要保證消息的可靠接收,需要將enable.auto.commit設置爲false,防止程序自動提交,應該由應用程序處理完成後手動提交。
示例:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "testsub");
props.put("enable.auto.commit", "false");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<String,String>(props);
consumer.subscribe(Arrays.asList("test.testTopic","testsub"));

while (true) {
   ConsumerRecords<String, String> records = consumer.poll(100);
   Map<TopicPartition,OffsetAndMetadata> commitMap = new HashMap(10);
   for (ConsumerRecord<String, String> record : records) {
      logger.info(record.value()); //模擬消息
      commitMap.put(new TopicPartition(record.topic(),record.partition()),new OffsetAndMetadata(record.offset()+1));
   }
   if(commitMap.isEmpty()){
      continue;
    }
    consumer.commitSync(commitMap);
}
 

 

存儲可靠性

刷盤時機

broker的刷盤時機主要是以下兩個參數控制:
log.flush.interval.ms 日誌刷盤的時間間隔,每隔多少時間將消息刷到磁盤上
log.flush.interval.messages 日誌刷盤的消息量,每積累多少條消息將消息刷到磁盤上

副本數

在創建消息Topic的時候需要指定消息的副本數 replicas
一般建議設置成3保證消息的可靠,再結合客戶端發送方的ack參數,當ack參數設置爲0表示不等待broker響應就發送下一條消息,當ack設置爲1則表示需要等待leader響應,當ack設置爲all則表示需要等待所有的replicas ISR都響應後才返回響應,其中all是最高可靠級別了,但是同時也降低了吞吐率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章