2018-12-22
最近在往ES里寫數(shù)據(jù)的時候,發(fā)現(xiàn)一條一條寫非常慢猫十。基本一個比較小規(guī)模(3master、3data炫彩、1client)的ES集群on k8s匾七,用RestHighLevelClient寫入數(shù)據(jù),加上一些業(yè)務(wù)邏輯江兢,每秒只能寫到30條左右昨忆。
線上環(huán)境有一張3500w的表,這樣寫實在不能忍杉允,于是換成ES的bulk request邑贴,發(fā)現(xiàn)速度快了很多,每秒5000條叔磷。
我們是這樣設(shè)置的拢驾,由于ES對bulk request的一次請求大小有限制,要求在20M以內(nèi)改基,所以我們采用1000條作為一個bulk繁疤,目前看效果很不錯,應(yīng)該還可以繼續(xù)優(yōu)化秕狰,要求是200w/s稠腊,還有一定差距。鸣哀。架忌。
2018-01-17
ES官方推薦的一次bulk size介于5-15MB之間,請求個數(shù)是1000-5000個
但是實際環(huán)境里我衬,一條數(shù)據(jù)的大小是不確定的叹放,而且不同規(guī)模的集群,bulk的大小也不一樣挠羔,具體設(shè)置還是要看情況
不過有這樣一個辦法井仰,可以大致估計一個請求的大小
將這個請求序列化出來,然后看大小褥赊,達到最佳size后就發(fā)送
這樣有幾個問題:
- 每個數(shù)據(jù)都執(zhí)行這個操作嗎糕档?
- 序列化本身就是一件很耗cpu的事情,這樣不會很慢嗎拌喉?
- 序列化以后的數(shù)據(jù)要占據(jù)的空間是MB級別,回收這個空間的消耗值得嗎俐银?
這個問題比較有意思尿背,spark的代碼里有一個類 SizeEstimator,他的用途其實和我們的需要是一樣的捶惜,用來估計一個對象在內(nèi)存中的大小田藐,但是有個問題,他估計的是這個對象。如果這個對象有一個字段是指針汽久,那這個指針指向的另一個對象也會被序列化鹤竭,有空可以研究一下,如何改進這個類景醇,達到我們的目的臀稚。
在索引數(shù)據(jù)過程中,經(jīng)常發(fā)現(xiàn)三痰,即使使用了最佳的bulk size吧寺,也不能達到最快的速度,因為我們的數(shù)據(jù)來源雖然是impala數(shù)據(jù)散劫,但是實現(xiàn)上并沒有使用impala的JDBC接口稚机。而是直接用HDFS的FileSystem打開文件流,理論上最快的速度應(yīng)該達到文件流的速度获搏,然而實際上遠遠沒有赖条。目前的測試情況,最快的速度也只有1w條數(shù)據(jù)/s常熙,與目標相差甚遠??纬乍。
所以目前的設(shè)計方案除了繼續(xù)優(yōu)化代碼,減少不必要的性能損失以外症概,還有一個想法就是集群化蕾额,并且多線程化,大概設(shè)想如下:
- 首先每個任務(wù)有自己的線程池彼城,在集群啟動時诅蝶,預(yù)估整個集群的資源,并按需分配募壕,這部分可以參考spark的邏輯调炬,然后以文件數(shù)為例,對impala數(shù)據(jù)來說舱馅,最終數(shù)據(jù)都存在HDFS上缰泡,所以可以先查看HDFS的數(shù)據(jù)集文件大小,大概每個block的量(256MB)代嗤,作為一個線程去做索引棘钞,如果這個表含有的數(shù)據(jù)大小約等于3個block,實際上是5份文件干毅,那就起3個線程宜猜,平均每個線程分得的數(shù)據(jù)量最好一致,以此類推硝逢。
- 集群化則是說姨拥,可以有一個service提供服務(wù)绅喉,然后索引實例有n個,沒有master叫乌,最好彼此之間互不影響柴罐,并且能夠完成任務(wù)的自動調(diào)度,能夠統(tǒng)一提供索引服務(wù)憨奸,最大化利用資源革屠,讓索引速度快起來。