1. 程式人生 > >eBay Elasticsearch效能優化實踐

eBay Elasticsearch效能優化實踐

摘要:Elasticsearch是基於Apache Lucene的開源搜尋和分析引擎,允許使用者以近乎實時的方式儲存,搜尋和分析資料。雖然Elasticsearch專為快速查詢而設計,但其效能在很大程度上取決於用於應用程式的場景,索引的資料量以及應用程式和使用者查詢資料的速率。這篇文章概述了挑戰和調優過程,以及Pronto團隊以戰略方式構建應對挑戰的工具。它還以各種圖形配置展示了進行基準測試的一些結果。以下是譯文。

Elasticsearch是基於Apache Lucene的開源搜尋和分析引擎,允許使用者以近乎實時的方式儲存,搜尋和分析資料。Pronto是在eBay網站上託管Elasticsearch叢集的平臺,該平臺使得eBay網內部客戶易於部署,操作用於全文搜尋,實時分析和日誌/事件監控的大規模的Elasticsearch。當前Pronto平臺管理著60多個Elasticsearch叢集和2000多個節點,日採集量達到180億份文件,日均搜尋請求達到35億份。平臺提供從條款,補救以及安全到監控,報警和診斷的全方位的資訊。

雖然Elasticsearch專為快速查詢而設計,但其效能在很大程度上取決於用於應用程式的場景,索引的資料量以及應用程式和使用者查詢資料的速率。這篇文章概述了挑戰和調優過程,以及Pronto團隊以戰略方式構建應對挑戰的工具。它還以各種圖形配置展示了進行基準測試的一些結果。

挑戰

迄今為止所觀察到的Pronto / Elasticsearch使用案例面臨的挑戰包括:

  1. 高吞吐量:一些叢集每天攝取高達5TB的資料,一些叢集每天的搜尋請求超過4億。如果Elasticsearch無法及時處理這些請求,那麼這些請求將在上游累積。
  2. 搜尋延遲低:對於效能關鍵的叢集,尤其是面向站點的系統,低搜尋延遲的特性是必須具有的,否則使用者體驗將會受到影響。
  3. 由於資料或查詢是可變的,所以最佳設定總是在變化。所有情況都沒有最佳設定。例如,將索引拆分成更多的分片(代表索引分片,Elasticsearch可以把一個完整的索引分成多個分片,這樣的好處是可以把一個大的索引拆分成多個,分佈到不同的節點上。構成分散式搜尋。分片的數量只能在索引建立前指定,並且索引建立後不能更改。)對於耗時的查詢是很有好處的,但是這可能會損害其它查詢效能。

解決方案

為了幫助客戶應對這些挑戰,Pronto團隊從使用者案例開始入手並持續整個叢集生命週期,構建效能測試、調優和監控的戰略方法。

  1. 評估叢集大小:在一個新的使用者案例部署之前,收集客戶提供的資訊,諸如吞吐量,文件大小,文件數量和搜尋型別,以評估Elasticsearch叢集的初始大小。
  2. 優化索引設計:與客戶一起評審索引設計。
  3. 調優索引效能:根據使用者場景調優索引效能和搜尋效能。
  4. 調優搜尋效能:使用使用者真實資料/查詢執行效能測試,用Elasticsearch配置引數的組合比較和分析測試結果。
  5. 執行效能測試:在案例啟動以後,叢集將受到監控,每當資料發生變化,查詢更改或者流量增加時,使用者都可以自由地重新執行效能測試。

評估叢集大小

Pronto團隊為每種型別的機器和每個支援的Elasticsearch版本執行基準測試,以收集效能資料,然後將其與客戶提供的資訊一起用於評估叢集的初始大小,這些資訊包括:

  • 索引吞吐量
  • 文件大小
  • 搜尋吞吐量
  • 查詢型別
  • 熱索引文件計數
  • 保留策略
  • 響應時間要求
  • SLA級別

優化索引設計

在開始攝取資料並執行查詢之前,請三思而後行。索引代表著什麼?Elastic的官方回答是“具有相似特徵的文件集合”。那麼下一個問題是“應該使用哪些特徵來對資料進行分組?應該把所有檔案放入一個索引還是多個索引呢?”答案是,這取決於所使用的查詢。下面是關於如何根據最常用的查詢分組索引的一些建議。

  • 如果查詢有一個過濾欄位並且它的值是可列舉的,那麼把資料分成多個索引。例如,有大量的全球產品資訊被攝取到Elasticsearch中,大多數查詢都有一個過濾子句“region”(區域),並且很少有機會執行跨區域查詢。查詢主體可以優化為:
    {
        "query": {
            "bool": {
                "must": {
                    "match": {
                        "title": "${title}"
                    }
                },
                "filter": {
                    "term": {
                        "region": "US"
                    }
                }
            }
        }
    }

在這種情況下,如果索引按照美國,歐洲等地區分成幾個較小的索引,就可以獲得更好的效能。然後可以從查詢中刪除過濾子句。如果需要執行一個跨區域查詢,可以將多個索引或萬用字元傳遞給Elasticsearch。

  • 如果查詢具有過濾欄位並且其值不可列舉,請使用路由。可以通過使用過濾欄位值作為路由鍵來將索引拆分成多個分片,然後刪除過濾條件。關於ElasticSearch裡的路由功能請參見這篇文章

    例如,Elasticsearch有數以百萬計的訂單,大多數查詢需要通過買家ID查詢訂單。為每個買家建立索引是不可能的,所以不能通過買家ID將資料拆分成多個索引。一個合適的解決方案是使用路由將具有相同買家ID的所有訂單放入同一個分片中,然後幾乎所有的查詢都可以在匹配路由鍵的分片內完成。

  • 如果查詢具有日期範圍過濾條件,則按日期分組資料。這適用於大多數日誌記錄或監控場景。可以以每天,每週或每月分組索引,然後可以在指定的日期範圍內獲得索引列表。Elasticsearch只需要查詢一個較小的資料集而不是整個資料集。此外,當資料過期時,很容易縮小/刪除舊的索引。

  • 明確地設定對映。Elasticsearch可以動態地建立對映,但可能並不適用於所有場景。例如,Elasticsearch 5.x中預設的字串欄位對映是“關鍵字”和“文字”型別,這在很多場景下是沒有必要的。

  • 如果文件使用使用者定義的ID或路由索引,請避免不平衡分片。 Elasticsearch採用隨機ID生成器和雜湊演算法來確保文件均勻地分配給分片。當使用使用者定義的ID或路由時,ID或路由鍵可能不夠隨機,並且一些分片可能明顯比其它分片更大。在這種情況下,在這個分片上的讀/寫操作將比在其它分片上慢得多。可以優化ID /路由鍵或使用index.routing_partition_size (在5.3和更高版本中可用)。

  • 使分片均勻分佈在節點上。如果一個節點比其它節點有更多的分片,則會比其它節點承擔更多的負載,並很有可能成為整個系統的瓶頸。

調優索引效能

用於索引諸如日誌和監控之類的重場景,索引效能是關鍵指標。這裡有一些建議:

  • 使用批量請求
  • 使用多個執行緒/工作來發送請求
  • 增加重新整理間隔。每次重新整理事件發生時,Elasticsearch都會建立一個新的Lucene段,並在稍後進行合併。增加重新整理間隔將降低建立/合併的成本。請注意,只有在重新整理事件發生後才能進行檔案搜尋。
    這裡寫圖片描述

    效能和重新整理間隔之間的關係

從上圖可以看出,隨著重新整理間隔的增大,吞吐量增加,響應時間變快。可以使用下面的請求來檢查有多少段以及重新整理和合並花費了多少時間。

Index/_stats?filter_path= indices.**.refresh,indices.**.segments,indices.**.merges
  • 減少副本數量。Elasticsearch需要為每個索引請求將文件寫入主要和所有副本分片。顯然,一個大的副本數會減慢索引速度,但另一方面,增加副本數量將提高搜尋效能。這個話題將在本文後面討論。副本的作用一是提高系統的容錯性,當某個節點某個分片損壞或丟失時可以從副本中恢復;二是提高Elasticsearch的查詢效率,Elasticsearch會自動對搜尋請求進行負載均衡

    這裡寫圖片描述
    效能和副本數量之間的關係

從上面的圖中,可以看到隨著副本數量的增加,吞吐量下降,響應時間也變慢。

  • 如果可能,使用自動生成的ID。 Elasticsearch自動生成的ID可以確保是唯一的,以避免版本查詢。如果客戶真的需要使用自定義的ID,建議選擇一個對Lucene友好的ID,比如零填充順序ID,UUID-1或者Nano time。這些ID具有一致的順序模式,壓縮良好。相比之下,像UUID-4這樣的ID本質上仍舊是隨機的,它提供了較差的壓縮比,並降低了Lucene的速度。

調優搜尋效能

使用Elasticsearch的主要原因是其支援通過資料進行搜尋。使用者應該能夠快速地找到所需要查詢的資訊。搜尋效能取決於很多因素:

  • 如果可能的話,使用過濾語境而不是查詢語境。一個查詢子句用於回答“這個文件如何與查詢子句匹配?” ,過濾子句用於回答“這個文件是否匹配這個過濾子句?”。Elasticsearch只需要回答“是”或“否”。它不需要計算過濾子句的相關性得分,並且可以快取記憶體過濾結果。有關詳細資訊,請參閱查詢和過濾語境
    這裡寫圖片描述
比較查詢和過濾
  • 增加重新整理間隔。正如在調優索引效能部分所提到的,Elasticsearch每次重新整理時都會建立一個新的段。增加重新整理間隔將有助於減少段數並降低搜尋的IO成本。而且一旦發生重新整理並且資料改變,快取將無效。增加重新整理間隔可以使Elasticsearch更高效地利用快取。

  • 增加副本數量。Elasticsearch可以在主分片或副本分片上執行搜尋。擁有的副本越多,搜尋中涉及的節點就越多。

這裡寫圖片描述
效能和副本數量之間的關係

從上圖可以看出,搜尋吞吐量幾乎與副本數量成線性關係。注意在這個測試中,測試叢集有足夠的資料節點來確保每個分片都有一個獨佔節點,如果這個條件不能滿足,搜尋吞吐量就不會那麼好。

  • 嘗試不同的分片數量。“應該為索引設定多少分片?” 這可能是最常見的問題。不幸的是,所有場景都沒有標準的數字,這完全取決於當時的實際情況。

太小的分片數量會使搜尋無法擴充套件。例如,如果分片數量設定為1,則索引中的所有文件都將儲存在一個分片中。對於每個搜尋,只能涉及一個節點。如果有很多檔案,那是很耗費時間的。另一方面,建立索引的分片太多也會對效能造成危害,因為Elasticsearch需要在所有分片上執行查詢,除非在請求中指定了路由鍵,然後將所有返回的結果一起取出併合並。

根據經驗來說,如果索引小於1G,可以將分片數設定為1。對於大多數情況,可以將分片數保留為預設值5,但是如果分片大小超過30GB,應該增加分片數量將索引分成更多的分片。建立索引後,分片數量不能更改,但是可以建立新的索引並使用reindex API轉移資料。

在這裡測試了一個擁有1億個文件,大約150GB的索引,使用了100個執行緒傳送搜尋請求。

這裡寫圖片描述
效能和分片數量之間的關係

從上圖中可以看出,優化後的分片數量為11個。開始的時候,搜尋吞吐量增加(響應時間減少),但隨著分片數量的增加,搜尋吞吐量減少(響應時間增加)。

請注意,在這個測試中,就像在副本數量測試中一樣,每個分片都有一個獨佔節點。如果這個條件不能滿足,搜尋吞吐量就不會像上圖所示那樣好。

在這種情況下,建議嘗試一個小於優化值的分片數,因為如果使用大分片數,並且使每個分片都有一個獨佔資料節點,那麼就需要很多個節點。

  • 節點查詢快取節點查詢快取只快取正在過濾語境中使用的查詢。與查詢子句不同,過濾子句是“是”或“否”的問題。Elasticsearch使用一個位設定機制來快取過濾結果,以便後面的查詢使用相同的過濾條件進行加速。請注意,只有儲存超過10,000個文件的分段(或文件總數的3%,以較大者為準)才能啟用節點查詢快取。有關快取的更多詳細資訊,請參閱關於快取

可以使用下面的請求來檢驗一個節點查詢快取是否有效。

GET index_name/_stats?filter_path=indices.**.query_cache
{
  "indices": {
    "index_name": {
      "primaries": {
        "query_cache": {
          "memory_size_in_bytes": 46004616,
          "total_count": 1588886,
          "hit_count": 515001,
          "miss_count": 1073885,
          "cache_size": 630,
          "cache_count": 630,
          "evictions": 0
        }
      },
      "total": {
        "query_cache": {
          "memory_size_in_bytes": 46004616,
          "total_count": 1588886,
          "hit_count": 515001,
          "miss_count": 1073885,
          "cache_size": 630,
          "cache_count": 630,
          "evictions": 0
        }
      }
    }
  }
}
  • 分片查詢快取。如果大多數查詢是聚合查詢,應該看看分片查詢快取,它可以快取聚合結果,以便Elasticsearch直接以低成本提供請求。有幾件事情需要注意:

    o 設定“size”:0。分片查詢快取只快取聚合結果和建議。它不會快取操作過程,因此如果將大小設定為非零,則無法從快取中獲益。

    o 有效負載JSON必須相同。分片查詢快取使用JSON主體作為快取鍵,因此需要確保JSON主體不會更改,並確保JSON主體中的鍵具有相同的順序。

    o Round日期時間。不要直接在查詢中使用像Date.now這樣的變數,Round它。否則,每個請求都會有不同的有效負載主體,從而導致快取始終無效。建議Round日期時間為小時或天,以便更有效地利用快取。

可以使用下面的請求來檢驗分片查詢快取是否有效果。

GET index_name/_stats?filter_path=indices.**.request_cache
{
  "indices": {
    "index_name": {
      "primaries": {
        "request_cache": {
          "memory_size_in_bytes": 0,
          "evictions": 0,
          "hit_count": 541,
          "miss_count": 514098
        }
      },
      "total": {
        "request_cache": {
          "memory_size_in_bytes": 0,
          "evictions": 0,
          "hit_count": 982,
          "miss_count": 947321
        }
      }
    }
  }
}
  • 僅檢索必要的欄位。如果文件很大,並且只需要幾個欄位,請使用 stored_fields 檢索所需要的欄位而不是所有欄位。

  • 避免搜尋停用詞。諸如“a”和“the”這樣的停用詞可能導致查詢命中結果計數爆炸。設想有一百萬個檔案,搜尋“fox”可能會返回幾十個結果,但搜尋“the fox”可能會返回索引中的所有檔案,因為“the”出現在幾乎所有的檔案中。Elasticsearch需要對所有命中的結果進行評分和排序,導致像“the fox”這樣的查詢減慢整個系統。可以使用停止標記過濾來刪除停用詞,或使用“和”運算子將查詢從“the fox”更改為“the AND fox”,以獲得更精確的結果。

如果某些詞在索引中經常使用,但不在預設停用詞列表中,則可以使用截止頻率來動態處理它們。

  • 如果不關心文件返回的順序,則按_doc排序。Elasticsearch使用“_score”欄位按預設分數排序。如果不關心順序,可以使用“sort”:“_doc”讓Elasticsearch按索引順序返回。

  • 避免使用指令碼查詢來計算不固定的匹配。在索引時儲存計算的欄位。例如,有一個包含大量使用者資訊的索引,需要查詢以“1234”開頭的所有使用者。或許想執行一個指令碼查詢,如“source”:“doc [‘num’].value.startsWith(’1234’)。” 這個查詢是非常耗費資源的,並且減慢整個系統。索引時考慮新增一個名為“num_prefix”的欄位,然後只需要查詢“name_prefix”:“1234”。

  • 避免萬用字元查詢

執行效能測試

對於每一次改變,都需要執行效能測試來驗證變更是否適用。因為Elasticsearch是一個restful服務(基於RESTful web介面),所以可以使用諸如Rally,Apache Jmeter和Gatling等工具來執行效能測試。因為Pronto團隊需要在每種型別的機器和Elasticsearch版本上執行大量的基準測試,而且需要在許多Elasticsearch叢集上執行Elasticsearch配置引數組合的效能測試,所以這些工具並不能滿足需求。

Pronto團隊構建了基於Gatling的線上效能分析服務 ,幫助客戶和我們執行效能測試並進行迴歸。該服務提供的功能使我們能夠:

  1. 輕鬆新增/編輯測試。使用者可以根據自己的輸入查詢或文件結構生成測試,而無需具有Gatling或Scala知識。
  2. 按順序執行多個測試,無需人工干預。它可以檢查狀態並在每次測試之前/之後更改Elasticsearch設定。
  3. 幫助使用者比較和分析測試結果分析。測試期間的測試結果和叢集統計資訊將保留下來,並可以通過預定義的Kibana視覺化進行分析。
  4. 從命令列或Web UI執行測試。Rest API還提供了與其它系統的整合功能。

下圖是架構

這裡寫圖片描述
效能測試服務架構

使用者可以檢視每個測試的Gatling報告,並檢視Kibana預定義的視覺化影象,以便進一步分析和比較,如下圖所示。

這裡寫圖片描述
Gatling報告
這裡寫圖片描述
Gatling報告

總結

本文概述了索引/分片/副本設計以及在設計Elasticsearch叢集時應該考慮的一些其它配置,以滿足攝取和搜尋效能的高期望。它還說明了Pronto團隊如何在戰略上幫助客戶進行初始規模調整,索引設計和調優以及效能測試。截至今天,Pronto團隊已經幫助包括訂單管理系統(OMS)和搜尋引擎優化(SEO)在內的眾多客戶實現了苛刻的效能目標,從而為eBay的關鍵業務做出了貢獻。

Elasticsearch的效能取決於很多因素,包括文件結構,文件大小,索引設定/對映,請求率,資料集的大小,查詢命中計數等等。針對一種情況的效能優化推薦不一定適用於另一種情況。徹底地測試效能,收集遙測資料,根據工作負載調整配置以及優化以滿足效能要求非常重要。