ElasticSearch性能優化

1、搜索效率優化

批量提交

  當有大量數據提交的時候,建議採用批量提交。html

好比在作 ELK 過程當中 ,Logstash indexer 提交數據到 Elasticsearch 中 ,batch size 就能夠做爲一個優化功能點。可是優化 size 大小須要根據文檔大小和服務器性能而定。緩存

像 Logstash 中提交文檔大小超過 20MB ,Logstash 會請一個批量請求切分爲多個批量請求。服務器

若是在提交過程當中,遇到 EsRejectedExecutionException 異常的話,則說明集羣的索引性能已經達到極限了。這種狀況,要麼提升服務器集羣的資源,要麼根據業務規則,減小數據收集速度,好比只收集 Warn、Error 級別以上的日誌。數據結構

優化硬件

  優化硬件設備一直是最快速有效的手段。併發

  1. 在經濟壓力能承受的範圍下, 儘可能使用固態硬盤 SSD。SSD 相對於機器硬盤,不管隨機寫仍是順序寫,都較大的提高。
  2. 磁盤備份採用 RAID0。由於 Elasticsearch 在自身層面經過副本,已經提供了備份的功能,因此不須要利用磁盤的備份功能,同時若是使用磁盤備份功能的話,對寫入速度有較大的影響。

增長 Refresh 時間間隔

  爲了提升索引性能,Elasticsearch 在寫入數據時候,採用延遲寫入的策略,即數據先寫到內存中,當超過默認 1 秒 (index.refresh_interval)會進行一次寫入操做,就是將內存中 segment 數據刷新到操做系統中,此時咱們才能將數據搜索出來,因此這就是爲何 Elasticsearch 提供的是近實時搜索功能,而不是實時搜索功能。elasticsearch

固然像咱們的內部系統對數據延遲要求不高的話,咱們能夠經過延長 refresh 時間間隔,能夠有效的減小 segment 合併壓力,提供索引速度。在作全鏈路跟蹤的過程當中,咱們就將 index.refresh_interval 設置爲 30s,減小 refresh 次數。分佈式

同時,在進行全量索引時,能夠將 refresh 次數臨時關閉,即 index.refresh_interval 設置爲 -1,數據導入成功後再打開到正常模式,好比 30s。ide

減小副本數量

  Elasticsearch 默認副本數量爲 3 個,雖然這樣會提升集羣的可用性,增長搜索的併發數,可是同時也會影響寫入索引的效率。性能

在索引過程當中,須要把更新的文檔發到副本節點上,等副本節點生效後在進行返回結束。使用 Elasticsearch 作業務搜索的時候,建議副本數目仍是設置爲 3 個,可是像內部 ELK 日誌系統、分佈式跟蹤系統中,徹底能夠將副本數目設置爲 1 個。fetch

 

2、查詢效率優化

路由

當咱們查詢文檔的時候,Elasticsearch 如何知道一個文檔應該存放到哪一個分片中呢?它實際上是經過下面這個公式來計算出來

shard = hash(routing) % number_of_primary_shards

routing 默認值是文檔的 id,也能夠採用自定義值,好比用戶 id。

不帶 routing 查詢

在查詢的時候由於不知道要查詢的數據具體在哪一個分片上,因此整個過程分爲 2 個步驟

  • 分發:請求到達協調節點後,協調節點將查詢請求分發到每一個分片上。
  • 聚合: 協調節點蒐集到每一個分片上查詢結果,在將查詢的結果進行排序,以後給用戶返回結果。

帶 routing 查詢

查詢的時候,能夠直接根據 routing 信息定位到某個分配查詢,不須要查詢全部的分配,通過協調節點排序。

向上面自定義的用戶查詢,若是 routing 設置爲 userid 的話,就能夠直接查詢出數據來,效率提高不少。

Filter VS Query

Ebay 曾經分享過他們使用 Elasticsearch 的經驗中說到:

Use filter context instead of query context if possible.
儘量使用過濾器上下文(Filter)替代查詢上下文(Query

  • Query:此文檔與此查詢子句的匹配程度如何?
  • Filter:此文檔和查詢子句匹配嗎?

Elasticsearch 針對 Filter 查詢只須要回答「是」或者「否」,不須要像 Query 查詢一下計算相關性分數,同時 Filter 結果能夠緩存。

大翻頁

  在使用 Elasticsearch 過程當中,應儘可能避免大翻頁的出現。

正常翻頁查詢都是從 From 開始 Size 條數據,這樣就須要在每一個分片中查詢打分排名在前面的 From + Size 條數據。協同節點收集每一個分配的前 From + Size 條數據。協同節點一共會受到 N * ( From + Size )條數據,而後進行排序,再將其中 From 到 From + Size 條數據返回出去。

若是 From 或者 Size 很大的話,致使參加排序的數量會同步擴大不少,最終會致使 CPU 資源消耗增大。

能夠經過使用 Elasticsearch scroll 和 scroll-scan 高效滾動的方式來解決這樣的問題。具體寫法,能夠參考 Elasticsearch: 權威指南 - scroll 查詢

3、JVM配置優化

32G 現象

  Elasticsearch 默認安裝後設置的堆內存是 1 GB。 對於任何一個業務部署來講, 這個設置都過小了。

好比機器有 64G 內存,那麼咱們是否是設置的越大越好呢?

其實不是的。

  主要 Elasticsearch 底層使用 Lucene。Lucene 被設計爲能夠利用操做系統底層機制來緩存內存數據結構。 Lucene 的段是分別存儲到單個文件中的。由於段是不可變的,這些文件也都不會變化,這是對緩存友好的,同時操做系統也會把這些段文件緩存起來,以便更快的訪問。

若是你把全部的內存都分配給 Elasticsearch 的堆內存,那將不會有剩餘的內存交給 Lucene。 這將嚴重地影響全文檢索的性能。

標準的建議是把 50% 的可用內存做爲 Elasticsearch 的堆內存,保留剩下的 50%。固然它也不會被浪費,Lucene 會很樂意利用起餘下的內存。

同時瞭解過 ES 的同窗都聽過過「不要超過 32G」的說法吧。

其實主要緣由是 :JVM 在內存小於 32 GB 的時候會採用一個內存對象指針壓縮技術。

在 Java 中,全部的對象都分配在堆上,並經過一個指針進行引用。 普通對象指針(OOP)指向這些對象,一般爲 CPU 字長 的大小:32 位或 64 位,取決於你的處理器。指針引用的就是這個 OOP 值的字節位置。

對於 32 位的系統,意味着堆內存大小最大爲 4 GB。對於 64 位的系統, 可使用更大的內存,可是 64 位的指針意味着更大的浪費,由於你的指針自己大了。更糟糕的是, 更大的指針在主內存和各級緩存(例如 LLC,L1 等)之間移動數據的時候,會佔用更多的帶寬.

因此最終咱們都會採用 31 G 設置

-Xms 31g -Xmx 31g

假設你有個機器有 128 GB 的內存,你能夠建立兩個節點,每一個節點內存分配不超過 32 GB。 也就是說不超過 64 GB 內存給 ES 的堆內存,剩下的超過 64 GB 的內存給 Lucene

相關文章
相關標籤/搜索