1、使用 bulk 批量寫入
你如果要往es里面灌入數據的話,那么根據你的業務場景來,如果你的業務場景可以支持讓你將一批數據聚合起來,一次性寫入es,那么就盡量采用bulk的方式,每次批量寫個幾千條這樣子。
bulk批量寫入的性能比你一條一條寫入大量的 document 的性能要好很多。但是如果要知道一個bulk請求最佳的大小,需要對單個 es node 的單個 shard 做壓測。
先 bulk 寫入 100 個 document,然后 200個,400個,以此類推,每次都將 bulk size 加倍一次。如果bulk寫入性能開始變平緩的時候,那么這個就是最佳的bulk大小。
並不是 bulk size 越大越好,而是根據你的集群等環境具體要測試出來的,因為越大的 bulk size 會導致內存壓力過大,因此最好一個請求不要發送超過 10MB 的數據量。
先確定一個是 bulk size,此時就盡量是 單線程,一個es node,一個 shard,進行測試。看看單線程最多一次性寫多少條數據,性能是比較好的。
2、使用多線程寫入 elasticsearch
單線程發送bulk請求是無法最大化es集群寫入的吞吐量的。
如果要利用集群的所有資源,就需要使用多線程並發將數據bulk寫入集群中。
為了更好的利用集群的資源,這樣多線程並發寫入,可以減少每次底層磁盤 fsync 的 次數 和 開銷。
首先對單個es節點的單個shard做壓測,比如說,先是2個線程,然后是4個線程,然后是8個線程,16個,每次線程數量倍增。
一旦發現es返回了 TOO_MANY_REQUESTS 的錯誤,JavaClient也就是 EsRejectedExecutionException。
此時那么就說明 es 是已經到了一個並發寫入的最大瓶頸了,此時我們就知道最多只能支撐這么高的並發寫入了。
3、禁用一些無用字段
1. 關閉 _all 配置選項,降低內存使用量以及提升寫入速度
2. 內存是寶貴的,每次創建索引的時候要做到充分利用,即
<1. 有的字段不用的我們堅決不索引
<2. 各個字段含義清晰就設置為最小類型
<3. 有些大文本字段如果只用於召回,不用於返回數據,盡可能的只索引不存儲
4、refresh 和 replia
這要分兩種情況來對待,分別為:全量重建索引 和 實時增量索引
全量重建索引
可以禁止 refresh 和 replica,即 index.refresh_interval = -1 & index.number_of_replicas = 0
<1. 此時就不需要創建 segment file,對應文件句柄少了,所消耗的資源也會降低很多
<2. 創建的 segment 文件少了,對應 merge 的壓力也會降下來
<3. 不需要將數據復制到其他的 replica shards 上面去,降低了保證數據一致性的耗時
此時寫入的速度會非常快。
一旦寫完之后,我們做完對應的 merge optimization 優化就可以將相關參數復原。
實時增量索引
默認的refresh間隔是 1s,用 index.refresh_interval 參數可以設置,這樣會其強迫 es 每秒中都將內存中的數據寫入磁盤中,創建一個新的segment file。
正是這個間隔,讓我們每次寫入數據后,1s以后就可以看到。
但是如果我們將這個間隔調大,比如30s,可以接受寫入的數據30s后才看到,那么我們就可以獲取更大的寫入吞吐量,因為30s內都是寫內存的,每隔30s才會創建一個segment file。
5、使用自動生成的 id
如果我們要手動給 es document 設置一個id,那么 es 需要每次都去確認一下那個id是否存在於相同的分片中,這個過程是比較耗費時間的。
如果我們使用自動生成的id,那么es就可以跳過這個步驟,寫入性能會更好。對於你的業務中的表id,可以作為 es document 的一個 field。
6、用性能更好的硬件設備
可以使用性能更好的 SSD 磁盤來替代 機械磁盤