Kafka參數調優

自己公司用到了kafka作爲MQ,在使用的時候需要設置很多參數,這裏便來總結一下Kafka參數的一些配置

1、一段Kafka生產端的示例代碼

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092"); 
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("buffer.memory", 67108864); 
props.put("batch.size", 131072); 
props.put("linger.ms", 100); 
props.put("max.request.size", 10485760); 
props.put("acks", "1"); 
props.put("retries", 10); 
props.put("retry.backoff.ms", 500);

KafkaProducer<String, String> producer = new KafkaProducer<String, String>(props);

2、內存緩衝的大小(buffer.memory)

Kafka的客戶端發送數據到服務器,一般都是要經過緩衝的,也就是說,你通過KafkaProducer發送出去的消息都是先進入到客戶端本地的內存緩衝裏,然後把很多消息收集成一個一個的Batch,再發送到Broker上去的。

所以這個“buffer.memory”的本質就是用來約束KafkaProducer能夠使用的內存緩衝的大小的,他的默認值是32MB。

那麼既然瞭解了這個含義,大家想一下,在生產項目裏,這個參數應該怎麼來設置呢?

你可以先想一下,如果這個內存緩衝設置的過小的話,可能會導致一個什麼問題?

首先要明確一點,那就是在內存緩衝裏大量的消息會緩衝在裏面,形成一個一個的Batch,每個Batch裏包含多條消息。

然後KafkaProducer有一個Sender線程會把多個Batch打包成一個Request發送到Kafka服務器上去。

那麼如果要是內存設置的太小,可能導致一個問題:消息快速的寫入內存緩衝裏面,但是Sender線程來不及把Request發送到Kafka服務器。

這樣是不是會造成內存緩衝很快就被寫滿?一旦被寫滿,就會阻塞用戶線程,不讓繼續往Kafka寫消息了。

所以對於“buffer.memory”這個參數應該結合自己的實際情況來進行壓測,你需要測算一下在生產環境,你的用戶線程會以每秒多少消息的頻率來寫入內存緩衝。

比如說每秒300條消息,那麼你就需要壓測一下,假設內存緩衝就32MB,每秒寫300條消息到內存緩衝,是否會經常把內存緩衝寫滿?經過這樣的壓測,你可以調試出來一個合理的內存大小。

3、多少數據打包爲一個Batch合適?

      接着你需要思考第二個問題,就是你的“batch.size”應該如何設置?這個東西是決定了你的每個Batch要存放多少數據就可以發送出去了。

      比如說你要是給一個Batch設置成是16KB的大小,那麼裏面湊夠16KB的數據就可以發送了。

      這個參數的默認值是16KB,一般可以嘗試把這個參數調節大一些,然後利用自己的生產環境發消息的負載來測試一下。

      比如說發送消息的頻率就是每秒300條,那麼如果比如“batch.size”調節到了32KB,或者64KB,是否可以提升發送消息的整體吞吐量。因爲理論上來說,提升batch的大小,可以允許更多的數據緩衝在裏面,那麼一次Request發送出去的數據量就更多了,這樣吞吐量可能會有所提升。

      但是這個東西也不能無限的大,過於大了之後,要是數據老是緩衝在Batch裏遲遲不發送出去,那麼豈不是你發送消息的延遲就會很高。比如說,一條消息進入了Batch,但是要等待5秒鐘Batch才湊滿了64KB,才能發送出去。那這條消息的延遲就是5秒鐘。所以需要在這裏按照生產環境的發消息的速率,調節不同的Batch大小自己測試一下最終出去的吞吐量以及消息的 延遲,設置一個最合理的參數。

4、要是一個Batch遲遲無法湊滿怎麼辦?

      要是一個Batch遲遲無法湊滿,此時就需要引入另外一個參數了,“linger.ms”他的含義就是說一個Batch被創建之後,最多過多久,不管這個Batch有沒有寫滿,都必須發送出去了。給大家舉個例子,比如說batch.size是16kb,但是現在某個低峯時間段,發送消息很慢。這就導致可能Batch被創建之後,陸陸續續有消息進來,但是遲遲無法湊夠16KB,難道此時就一直等着嗎?當然不是,假設你現在設置“linger.ms”是50ms,那麼只要這個Batch從創建開始到現在已經過了50ms了,哪怕他還沒滿16KB,也要發送他出去了。所以“linger.ms”決定了你的消息一旦寫入一個Batch,最多等待這麼多時間,他一定會跟着Batch一起發送出去。

     避免一個Batch遲遲湊不滿,導致消息一直積壓在內存裏發送不出去的情況。這是一個很關鍵的參數。這個參數一般要非常慎重的來設置,要配合batch.size一起來設置。舉個例子,首先假設你的Batch是32KB,那麼你得估算一下,正常情況下,一般多久會湊夠一個Batch,比如正常來說可能20ms就會湊夠一個Batch。那麼你的linger.ms就可以設置爲25ms,也就是說,正常來說,大部分的Batch在20ms內都會湊滿,但是你的linger.ms可以保證,哪怕遇到低峯時期,20ms湊不滿一個Batch,還是會在25ms之後強制Batch發送出去。

      如果要是你把linger.ms設置的太小了,比如說默認就是0ms,或者你設置個5ms,那可能導致你的Batch雖然設置了32KB,但是經常是還沒湊夠32KB的數據,5ms之後就直接強制Batch發送出去,這樣也不太好其實,會導致你的Batch形同虛設,一直湊不滿數據。

5、最大請求大小

      “max.request.size”這個參數決定了每次發送給Kafka服務器請求的最大大小,同時也會限制你一條消息的最大大小也不能超過這個參數設置的值,這個其實可以根據你自己的消息的大小來靈活的調整。

      給大家舉個例子,你們公司發送的消息都是那種大的報文消息,每條消息都是很多的數據,一條消息可能都要20KB。此時你的batch.size是不是就需要調節大一些?比如設置個512KB?然後你的buffer.memory是不是要給的大一些?比如設置個128MB?

只有這樣,才能讓你在大消息的場景下,還能使用Batch打包多條消息的機制。但是此時“max.request.size”是不是也得同步增加?因爲可能你的一個請求是很大的,默認他是1MB,你是不是可以適當調大一些,比如調節到5MB?

6、重試機制

“retries”和“retries.backoff.ms”決定了重試機制,也就是如果一個請求失敗了可以重試幾次,每次重試的間隔是多少毫秒。

這個大家適當設置幾次重試的機會,給一定的重試間隔即可,比如給100ms的重試間隔。

7、持久化機制

“acks”參數決定了發送出去的消息要採用什麼樣的持久化策略,這個涉及到了很多其他的概念。

首先這個acks參數,是在KafkaProducer,也就是生產者客戶端裏設置的。也就是說,你往kafka寫數據的時候,就可以來設置這個acks參數。然後這個參數實際上有三種常見的值可以設置,分別是:0、1 和 all。

第一種選擇是把acks參數設置爲0,意思就是我的KafkaProducer在客戶端,只要把消息發送出去,不管那條數據有沒有在哪怕Partition Leader上落到磁盤,我就不管他了,直接就認爲這個消息發送成功了。

如果你採用這種設置的話,那麼你必須注意的一點是,可能你發送出去的消息還在半路。結果呢,Partition Leader所在Broker就直接掛了,然後結果你的客戶端還認爲消息發送成功了,此時就會導致這條消息就丟失了。

第二種選擇是設置 acks = 1,意思就是說只要Partition Leader接收到消息而且寫入本地磁盤了,就認爲成功了,不管他其他的Follower有沒有同步過去這條消息了。

     這種設置其實是kafka默認的設置,大家請注意,劃重點!這是默認的設置也就是說,默認情況下,你要是不管acks這個參數,只要Partition Leader寫成功就算成功。

      但是這裏有一個問題,萬一Partition Leader剛剛接收到消息,Follower還沒來得及同步過去,結果Leader所在的broker宕機了,此時也會導致這條消息丟失,因爲人家客戶端已經認爲發送成功了。

最後一種情況,就是設置acks=all,這個意思就是說,Partition Leader接收到消息之後,還必須要求ISR列表裏跟Leader保持同步的那些Follower都要把消息同步過去,才能認爲這條消息是寫入成功了。

如果說Partition Leader剛接收到了消息,但是結果Follower沒有收到消息,此時Leader宕機了,那麼客戶端會感知到這個消息沒發送成功,他會重試再次發送消息過去。

此時可能Partition 2的Follower變成Leader了,此時ISR列表裏只有最新的這個Follower轉變成的Leader了,那麼只要這個新的Leader接收消息就算成功了。

8、acks參數小提示

acks=all 就可以代表數據一定不會丟失了嗎?

      當然不是,如果你的Partition只有一個副本,也就是一個Leader,任何Follower都沒有,你認爲acks=all有用嗎?當然沒用了,因爲ISR裏就一個Leader,他接收完消息後宕機,也會導致數據丟失。所以說,這個acks=all,必須跟ISR列表裏至少有2個以上的副本配合使用,起碼是有一個Leader和一個Follower纔可以。這樣才能保證說寫一條數據過去,一定是2個以上的副本都收到了纔算是成功,此時任何一個副本宕機,不會導致數據丟失。

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