ES寫入性能優化

NO IMAGE

背景: 有1億多的用戶畫像中數倉需要導入ES。大多數字段都是sql統計數據,無法區分哪些發生了變化,所以不能增量更新。只能每天全量刷數據。在刷數據的過程中出現了更新緩慢、內存問題。於是做了一些寫入優化。


解決方案

1. 讀數據

首先要從數倉讀取出數據到內存。然後再組裝對象去ES刷數據字段比較多而且都需要查詢。嘗試了一下,即使limit 10,也需要耗時2分鐘。所以第一步導數據不能直接查詢。採用的是數倉到分佈式文件系統分片存儲。這一步已經有現成工具。1億數據導入到分片耗時3分鐘左右

2.組裝數據

將分片的數據讀到java內存中。再構造請求參數刷ES

`問題:1.刷數據ES報413錯誤。ES建議每次bulk5~15M數據,這裡我每次批量提交5000條,bulk的時候發生的413 requets too large錯誤,google了一下,說是索引的時候段合併內存不夠。於是調整indices.breaker.fielddata.limit為60%,增大堆內存,結果沒什麼用;也有說要調整 client_max_body_size 的,但是我們的es是雲服務,沒法改配置參數最終加大es的內存為16G,不再報這個錯誤。

2.之前寫業務代碼數據量一般不是很大,採用的是一次性把數據讀取到內存中。再做業務處理。但是這次在數據塞到一半的數據,先是系統響應變慢了,後來測試環境的系統掛了。通過過命令排查,發現List對象佔用了很多空間。於是複查代碼。發現是for循環一直往list填對象導致的內存洩露。於是限制了單個文件大小為20M,一個文件一個文件地處理。
`

3.提高es索引效率

剛開始刷數據預計需要20個小時。今天的數據如果明天才更新完,意義不大。於是想辦法提高索引效率。網上都說”refresh_interval”: “-1″;調整number_of_replicas=0。我調整了結果沒什麼變化。於是採用多線程刷數據

問題:1.一開始使用size為20的無界隊列,導致耗盡資源,任務線程佔用的內存佔用了80+%的內存,其他任務可能被拖垮。後來線程的核心線程數和最大線程數統一設置為10。並採用future模式,一個任務完成後再去添加其他任務。解決了線程耗盡資源和內存的問題。

用htop查看刷數據機器的性能

ES寫入性能優化

可以看到開啟的10個線程佔用42%內存。主線程cpu偶爾接近100%,這不是io密集型嗎?怎麼會耗cpu。cpu變高可能是複雜的技術或者死循環。這裡循環每次讀取量有50000條,並且組裝對象的邏輯。而且有10個線程,猜想可能是這個原因。

ES的索引速率

ES寫入性能優化

成果

最後原來需要20小時才能完成的刷數據任務,只耗時約100分鐘。當然中間遇到的坑不止這些

相關文章

詳解CyclicBarrier

詳解CountDownLatch

線程池

第一次來到