bulk Java提交数据,性能优化 – bulk提交 - ELK Stack 中文指南
在 CRUD 章節,我們已經知道 ES 的數據寫入是如何操作的了。喜歡自己動手的讀者可能已經迫不及待的自己寫了程序開始往 ES 里寫數據做測試。這時候大家會發現:程序的運行速度非常一般,即使 ES 服務運行在本機,一秒鐘大概也就能寫入幾百條數據。
這種速度顯然不是 ES 的極限。事實上,每條數據經過一次完整的 HTTP POST 請求和 ES indexing 是一種極大的性能浪費,為此,ES 設計了批量提交方式。在數據讀取方面,叫 mget 接口,在數據變更方面,叫 bulk 接口。mget 一般常用于搜索時 ES 節點之間批量獲取中間結果集,對于 Elastic Stack 用戶,更常見到的是 bulk 接口。
bulk 接口采用一種比較簡樸的數據積累格式,示例如下:
# curl -XPOST http://127.0.0.1:9200/_bulk -d'
{ "create" : { "_index" : "test", "_type" : "type1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "type1" } }
{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value2" }
{ "update" : {"_id" : "1", "_type" : "type1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
'
格式是,每條 JSON 數據的上面,加一行描述性的元 JSON,指明下一行數據的操作類型,歸屬索引信息等。
采用這種格式,而不是一般的 JSON 數組格式,是因為接收到 bulk 請求的 ES 節點,就可以不需要做完整的 JSON 數組解析處理,直接按行處理簡短的元 JSON,就可以確定下一行數據 JSON 轉發給哪個數據節點了。這樣,一個固定內存大小的 network buffer 空間,就可以反復使用,又節省了大量 JVM 的 GC。
事實上,產品級的 logstash、rsyslog、spark 都是默認采用 bulk 接口進行數據寫入的。對于打算自己寫程序的讀者,建議采用 Perl 的 Search::Elasticsearch::Bulk 或者 Python 的 elasticsearch.helpers.* 庫。
bulk size
在配置 bulk 數據的時候,一般需要注意的就是請求體大小(bulk size)。
這里有一點細節上的矛盾,我們知道,HTTP 請求,是可以通過 HTTP 狀態碼 100 Continue 來持續發送數據的。但對于 ES 節點接收 HTTP 請求體的 Content-Length 來說,是按照整個大小來計算的。所以,首先,要確保 bulk 數據不要超過 http.max_content_length 設置。
那么,是不是盡量讓 bulk size 接近這個數值呢?當然不是。
依然是請求體的問題,因為請求體需要全部加載到內存,而 JVM Heap 一共就那么多(按 31GB 算),過大的請求體,會擠占其他線程池的空間,反而導致寫入性能的下降。
再考慮網卡流量,磁盤轉速的問題,所以一般來說,建議 bulk 請求體的大小,在 15MB 左右,通過實際測試繼續向上探索最合適的設置。
注意:這里說的 15MB 是請求體的字節數,而不是程序里里設置的 bulk size。bulk size 一般指數據的條目數。不要忘了,bulk 請求體中,每條數據還會額外帶上一行元 JSON。
以 logstash 默認的 bulk_size => 5000 為例,假設單條數據平均大小 200B ,一次 bulk 請求體的大小就是 1.5MB。那么我們可以嘗試 bulk_size => 50000;而如果單條數據平均大小是 20KB,一次 bulk 大小就是 100MB,顯然超標了,需要嘗試下調至 bulk_size => 500。
總結
以上是生活随笔為你收集整理的bulk Java提交数据,性能优化 – bulk提交 - ELK Stack 中文指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个显示器分两个屏幕_桌面改造计划2.0
- 下一篇: java美元兑换,(Java实现) 美元