一次Kafka記憶體泄露排查經過
一、現象
服務部署後記憶體總體呈上升趨勢
二、排查過程
通過go tool pprof收集了三天記憶體數據
2月11號數據:
2月14號數據:
2月15號數據:
可以看到newPartitionProducer持續增長,可定位到是kafka的問題。而newPartitionProducer是分區生產者,因此查看分區相關的數據。
最近增加的topic:ai_face_process_topic,這個是AI換臉的,每生成一個影片都要通過Kafka中轉消息到影片處理伺服器。
查閱資料庫看影片生成記錄。2022.1.25上線到今天2022.2.15一共20天,只增長了701個影片,平均每天35個影片。
但這個topic有64個分區。這是因為影片生成過程比較耗時,當時考慮到需要提高並發量,所以需要分區數比較多。
查看sarama客戶端的API程式碼,給每個分區發消息時會判斷這個分區的handler是否存在,不存在則創建。
sarama創建partition handler的關鍵程式碼:
handler := tp.handlers[msg.Partition] if handler == nil { handler = tp.parent.newPartitionProducer(msg.Topic, msg.Partition) tp.handlers[msg.Partition] = handler } |
且創建後需要手動close,否則記憶體一直佔用,這是官方說明:
而我們使用sarama客戶端的producer是全局的,一直不會close,所以會一直佔用記憶體。
再看看我們使用sarama的partitioner是NewRandomPartitioner,即每條消息隨機匹配到partition。
這樣,按照每天三十多的影片生成量,出現前幾天新增分配二三十個handler,逐漸減少,直到分配完64個handler。
每個handler會分配8MB記憶體,也就出現了上面的記憶體數據:152MB,264MB,172MB。
三、結論與優化
記憶體增長几天穩定後則不會繼續增長。
其他分區數比較多的topic沒有觀察到記憶體持續增長情況是因為數據量比較大,服務啟動沒多久就分配完了每個分區的handler。
優化:
單個AI換臉影片處理服務耗時較長,決定了我們需要比較大的並發量,所以後面分區數還可能增加。而64個分區已經使每個服務佔用64*8=504MB記憶體,嚴重影響擴展性。
因此後面ai_face_process_topic考慮遷移到redis做消息中轉。
四、參考鏈接: