中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解析Elasticsearch的查詢毛刺現象

發布時間:2021-12-10 11:30:14 來源:億速云 閱讀:288 作者:柒染 欄目:大數據

如何解析Elasticsearch的查詢毛刺現象,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

如果業務對查詢延遲很敏感,Elasticsearch 查詢延遲中的毛刺現象就是比較困擾的一類問題,由于出現毛刺的時間點已經過去,無法穩定復現,對于根因的分析比較困難,無法用系統化調試的思想,從現象出發逐步推理,定位問題,能做的通常就是看一下監控系統對應時間點的指標情況,而在 es 中,導致查詢延遲發生波動的因素非常多,今天我們來列舉一下可能的因素,并嘗試用對應的方法來定位和解決他們。

通常一個系統中會有多種不同的查詢同時存在,他們本身正常的查詢延遲就可能存較大差異,因此即使系統在理想狀態下,查詢延遲的曲線也可能存在較大波動,特別是查詢條件不固定,某些查詢本身就耗時較長。我們只討論一個特定的查詢語句在某個時刻產生了較大延遲,即這個查詢語句正常不應該耗時那么久。

另外 es 和 lucene 層面的查詢緩存只是一種優化,查詢緩存本身并不能保證查詢延遲。

GC 的影響

查詢延遲受 GC 的影響是常見因素之一,一個查詢被轉發的相關分片,任意節點產生一個長時間的 GC 都會導致整個查詢耗時變長。

定位方式:
查看對應時間點的節點 GC 指標,參考 kibana 或 gc log

解決方式:
堆內存不足可能的因素比較多,例如配置的 JVM內存較小,open 的索引過多,導致 FST 占用空間過大(未開啟 offheap 的情況下),聚合占用了大量內存,netty 層占用大量內存,以及 cache 占用的內存等,主要是根據自己的業務特點,找到內存被誰占用了,然后合理規劃JVM 內存空間。可以通過 REST API 或 MAT 分析內存,參考命令:

curl -sXGET "http://localhost:9200/_cat/nodes?h=name,port,segments.memory,segments.index_writer_memory,segments.version_map_memory,segments.fixed_bitset_memory,fielddata.memory_size,query_cache.memory_size,request_cache.memory_size&v"

HBase 通過 offheap 的方式降低 JVM 占用,來避免 FGC,es 將 FST offheap 后也大幅降低了 JVM 占用情況,不過 FST offheap 之后有可能會被系統清理,再次查詢 FST 就會發生 io,也會造成查詢延遲不穩定,不過這種概率非常小。而在 es 中聚合,scroll等操作都可能導致 JVM 被大幅占用,增加了不確定性。

系統 cache 失效

查詢,以及聚合,需要訪問磁盤上不同的文件,es 建議為系統 cache 保留一半的物理內存空間,當系統 cache 失效,發生磁盤 io,對查詢延遲產生明顯的影響。pagecache 什么時候會失效?使用 pagecache 的地方很多,linux 默認會緩存絕大部分的文件讀寫,例如查詢,寫日志,入庫寫 segment 文件,merge 時讀寫的文件,以及es 所在節點部署的其他的程序、腳本文件執行的對 io 上面的操作等都會搶占 pagecache。linux 按一定策略和閾值來清理 pagecache,應用層無法控制哪些文件不被清理。

因此我們需要了解一個查詢語句在 io 上的需求,主要是以下兩個問題:

  • 查詢過程需要實時讀取哪些文件?

  • 一次查詢需要幾次 io?讀取多少字節?消耗多少時間?

查詢過程需要實時讀取哪些文件

es 中的查詢是一個復雜的過程,不同的查詢類型需要訪問不同的 lucene 文件,我將常見類型的查詢可能訪問的文件整理如下:

如何解析Elasticsearch的查詢毛刺現象

真正查詢過程中,并非所有文件都會實時讀取,有些文件已經在 open 索引的時候讀取完畢常駐內存,有些元信息文件也是在 open 的時候解析一次。為了驗證搜索過程實際訪問的文件與預期是否一致,我寫了一個 systemtap 腳本來 hook 系統調用的 read 及 pread 函數,并把調用情況打印出來,驗證過程樣本數據使用 geonames 索引,為了便于演示,將索引 forcemerge 為單個分段,并將 store 設置為 niofs。

僅查詢,不取回
分布式搜索由兩階段組成,當請求中 size=0時,只執行查詢階段,不需要取回。因此 term 查詢或 match 查詢,因此查詢過程一般只需要用到倒排索引,因此,如下類型的查詢:

_search?size=0
{
 "query": {
   "match": {
     "name": {
       "query": "Farasi"
     }
   }
 }
}

只需要讀取 tim 文件。因為tip 是在內存常駐的,而 size=0的時候只需要返回 hit 數量,es 在實現的時候有一個提前終止的優化,直接從 tim 中取 docFreq 作為 hit,不需要訪問 postings list。

如何解析Elasticsearch的查詢毛刺現象

但是當查詢含有 post_filter ,自定義的terminate_after等情況時,不會走提前終止的優化過程。再者就是類似如下的多個查詢條件時,lucene 需要對每個字段的查詢結果做交并集,這就需要拿到 postings list才行:

_search?size=0
{
 "query": {
   "bool": {
     "must":     { "match": { "name": "Farasi" }},
     "must_not": { "match": { "feature_code": "CMP"  }}
   }
 }
}

因此會讀取 .doc 文件:

如何解析Elasticsearch的查詢毛刺現象

當 size!=0 時,term 查詢和 match 查詢需要讀取的文件不一樣,因此下面單獨討論。

term查詢,加取回
帶上 fetch 階段后,原來查詢過程需要訪問的文件不變,fetch 過程需要從 stored fields 中取,因為 _source 字段本身就是存儲到 stored fields 中的。

_search?size=1
{
 "query": {
   "term": {
     "country_code.raw": {
       "value": "CO"
     }
   }
 }
}

因此,需要相比僅查詢的過程,還需要多訪問 fdt,fdx文件。

如何解析Elasticsearch的查詢毛刺現象

match查詢,加取回

match 查詢由于需要計算評分,需要使用 Norms 信息,因此在 term 查詢加取回的基礎上還要多訪問 Norms 文件

_search?size=10
{
 "query": {
   "match": {
     "name": {
       "query": "Farasi"
     }
   }
 }
}

需要讀取 Norms中的 nvd 文件:

如何解析Elasticsearch的查詢毛刺現象

數值類型查詢
數值類型的字段使用 BKD-tree 建立索引,不會存儲到倒排,因此查詢過程需要讀取 Point Value。取回過程與 term 查詢相同。

_search?size=0
{
 "query": {
   "range": {
     "geonameid": {
       "gte": 3682501,
       "lte": 3682504
     }
   }
 }
}

查詢過程只需要讀取 dim 文件:

如何解析Elasticsearch的查詢毛刺現象

聚合

對于 metric 和 bucket 聚合,需要訪問的文件相同,當 size=0時,只需要讀取 dvd 文件。

_search?size=0
{
 "aggs": {
   "name": {
     "terms": { "field": "name.raw" }
   }
 }
}

以下為部分截圖,省略了后面的3萬多條記錄。

如何解析Elasticsearch的查詢毛刺現象

GET API

使用 GET API獲取單條文檔時,與 fetch 過程并不相同

_doc/IrOMznAB5onF36XmwY4W

以下結果想必會出乎意料:

如何解析Elasticsearch的查詢毛刺現象

?_id 字段是被建立了索引的。這個 _id 是 es 層面概念,并非 lucene 倒排表里的 docid,因此根據 _id 單條 GET 的時候,需要先執行一次 lucene 查詢(termsEnum.seekExact)來獲取 lucene 中數字類型的 docid,查詢過程自然需要查找 FST,讀取 tim。

然后根據這個 docid 去 stored field 中讀取 _source,因此需要讀取 fdx,fdt 文件

最后,GET API 除了返回 _source 之外,還要返回該文檔的元信息字段,包括:_version、_seq_no、_primary_term,這三個字段是保存在 docvalue 中的,因此需要讀取 dvd 文件。

兩階段的查詢過程中,query 階段返回的 docid 是 lucene 內部數字類型的 id,fetch 的時候可以直接獲取了。

查詢需要幾次 io?

在了解了查詢會涉及到動態讀取哪些文件之后,我們還需要知道在 io 上需要多大的代價,為了驗證實際搜索過程的 io 情況,我們再編寫一個新的 systemtap 腳本,將查詢過程對每個文件讀取的字節數,耗費時間等信息打印出來:

如何解析Elasticsearch的查詢毛刺現象

為了觀測到查詢在 io 上的影響,我們需要排除一些干擾因素:

無 pagecache 的測試:

  • 用 vmtouch 驅逐該索引在 pagecache 的緩存

  • 執行 _cache/clear 清理 es 層面的緩存

有 pagecache 的測試:

  • 執行 _cache/clear 清理 es 層面的緩存

  • 使用相同查詢執行第2次

此外,系統環境干凈,單節點,沒有寫入操作,沒有其他無關進程影響。然后對幾種常見類型的查詢進行統計,結果如下表:?

如何解析Elasticsearch的查詢毛刺現象

你可能不想看這種明細表,我來總結一下:多數查詢所需的 read 調用次數及需要讀取的數據量都不大,但是有兩種情況需要較多的 io,因為他們都與數據量有關:

  • 聚合的時候,所需 io 取決于參與聚合的數據量。

  • 數值類型的 range query,所需 io 取決于命中的結果集大小。

業務對于上述兩種類型的查詢要特別關注。可以考慮設法優化,例如聚合前盡量通過查詢條件縮小參與聚合的結果集,以及 range 查詢的時候盡量縮小范圍。其次還有兩種情況需要的 io 相對較多,但比上面的要少一個數量級:

  • 多條件查詢時,需要對多個字段的結果集做交并,結果集較大時,需要讀取doc 文件的次數較多,本例中有幾十次。

  • 深度翻頁,要取決于要取回的數據量。因為單條 GET 那讀那么多的文件,代價略大。

結論:在僅查詢的場景下,訪問 doc 和 dim 文件的次數可能會比較多,通常業務的查詢語句都比較復雜,混合多種查詢條件,io 量雖然是很大,但是當磁盤比較繁忙,而 page cache又未命中的情況下,查詢延遲可能會比較大。 

FST offheap 后的影響

FST 的 offheap 通過 mmap tip 文件,讓 FST 占用的內存空間從堆內轉向 pagecache 來實現,既然在 pagecache 中,當被 pagecache 驅逐后,就會產生 io,產生明顯的查詢延遲。簡單來說就是這種 offheap 的效果有可能導致 FST 不在 heap 了。

雖然 tip 被逐出 pagecache 的幾率很小,但是,隨著集群規模變大,偶然因素就會變成必現情況。

解決方式:自研一種 offheap也很簡單, FST 的查找過程就是在數組里跳來跳去的找,所以比 HBase 的 offheap 簡單很多。如果不想改代碼,解決方式參考上一條。

如何觀測查詢在 io 上的延遲

當生產環境查詢延遲產生毛刺,我們想要確定這個較高的延遲是否受 io 的影響導致,但是很不幸,目前還很難觀測到,即使查詢延遲毛刺發生在當下,Profile API 也無法給出在 io 上的耗時(通過 systemtap 腳本中為 pread 過程注入延遲,發現讀取 tim 文件的耗時在 Profile結果里體現不出來的,fdt,fdx文件的讀取延遲體現在create_weight字段,dim 文件的讀取延遲體現在build_scorer字段等,難以界定問題)發現如果想要觀測到這些指標,需要在 lucene 層面做出一些改進,然后在 Profile API 和 Slow log 中展示出來,而且還僅限于使用 niofs 的情況下才能拿到指標。

既然搜索需要不可控次數的 io,搜索延遲就注定是無法保障的。例如:

  • 索引寫入會占用io,雖然不多,但是存在瞬間刷盤的時刻

  • 如果有 update,會比 index 操作占用更多 io util

  • 如果存在巨大的 shard,查詢可能會占用較大 io util

  • 單個節點的多個磁盤之間可能是負載不均的。

  • merge,recovery,甚至更新集群狀態,都需要 io

磁盤 io 導致的問題,就用 ssd或內存來解決,HDFS 里將存儲類型分為 RAM,SSD,DISK 等幾種類型,再根據不同的存儲策略控制副本在不同存儲介質的分布,在 es 里也是類似的機制:

  • 第一種是索引級別的冷熱分離,用 node.attr 配合索引級別的 allocation策略來實現,讓熱索引存儲到 ssd,索引的寫入和查詢過程都不變。

  • 第二種可以考慮讓主分片放到 RAM,例如 /dev/shm,副分片放到 ssd 或普通磁盤,可以通過 awareness來實現,先為部分節點配置純 RAM 存儲,配置為hot,其他節點使用普通存儲,配置為cool,awareness會保證分片的不同副本放到不同區域,類似 hdfs 的機架感知。但是由于內存數據容易丟失,最好在寫入過程中將 wait_for_active_shards設置為 all,讀取的時候通過 preference來控制優先讀取 hot 節點。如果你就想要一個低延遲的搜索,把lucene 文件都加載到內存吧!

還有一種最簡單的是 vmtouch 等方式讓 lucene 文件被系統 cache住,但什么時候被清理不可預期。pagecache 命中率可以用 cachestat來查看,并且對 mmapfs 有效。

Search Queue 堆積

如果客戶端發送的查詢并發過高,導致 search 線程池占滿,查詢請求進入隊列等待,也會導致查詢過程產生較高延遲。

定位方式:
kinaba 中暫時還沒有關于線程池的指標,需要自己監控

解決方式:
控制好客戶端的查詢并發,客戶端的一個查詢請求如果涉及到某個數據節點的三個分片,就會在該節點占用3個 search 線程。目前指標上還看不到請求排隊花費的時間。

如何解析Elasticsearch的查詢毛刺現象

題外話:

es 使用 max_concurrent_shard_requests 參數來控制單個查詢請求在某個節點上的查詢并發,避免單個請求把整個集群的查詢資源占滿,協調節點在構建完本次查詢請求涉及的目的 shard 列表后,根據 max_concurrent_shard_requests 進行并發控制,超過并發的會放入到隊列中,不過這個隊列并不占用 search queue,因此即使并發受限,其查詢延遲不會受此因素影響。

總結

Lucene 并不是為低延遲而設計的系統,查詢毛刺主要受 GC 和 IO 的影響,GC 層面在于合理的規劃JVM內存,避免頻繁 GC 和 FGC,IO 層面的可以考慮使用 SSD,RAMDISK 或預留足夠的 pagecache來解決。

關于如何解析Elasticsearch的查詢毛刺現象問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

禹城市| 藁城市| 军事| 读书| 连云港市| 任丘市| 华蓥市| 乳源| 滦南县| 昔阳县| 赤城县| 星座| 沙雅县| 利川市| 措勤县| 广饶县| 平潭县| 五家渠市| 北碚区| 友谊县| 尚志市| 靖州| 武义县| 乌什县| 化德县| 宣恩县| 岫岩| 开化县| 云安县| 昌平区| 淮南市| 东平县| 营山县| 剑河县| 西林县| 洱源县| 平塘县| 桂阳县| 双辽市| 武安市| 景洪市|