1. 背景 日誌領域是Elasticsearch(ES)最重要也是規模最大的應用場景之一。這得益於 ES 有高性能倒排索引、靈活的 schema、易用的分散式架構,支持高吞吐寫入、高性能查詢,同時有強大的數據治理生態、端到端的完整解決方案。但原生 ES 在高吞吐寫入、低成本存儲、高性能查詢等方面還有 ...
1. 背景
日誌領域是Elasticsearch(ES)最重要也是規模最大的應用場景之一。這得益於 ES 有高性能倒排索引、靈活的 schema、易用的分散式架構,支持高吞吐寫入、高性能查詢,同時有強大的數據治理生態、端到端的完整解決方案。但原生 ES 在高吞吐寫入、低成本存儲、高性能查詢等方面還有非常大的優化空間,本文重點剖析騰訊雲大數據 ES 團隊在這三個方面的內核增強優化。
2. 日誌領域的挑戰
我們先來看看日誌領域的挑戰有哪些。
首先從日誌本身的數據特點來看,主要以半結構化、非結構化為主,傳統的資料庫方案沒法很好的解決解析、存儲等問題。ES 支持 JSON 且支持動態映射,高版本還支持 Runtime Feilds,能在查詢時動態提取欄位,天然支持了日誌場景複雜、靈活的數據結構。
日誌數據進入 ES 則面臨高併發、高吞吐的寫入性能挑戰。內核層面我們進行了定向路由、物理複製等重磅優化,有效解決日誌入口吞吐瓶頸,提升寫入性能一倍+。
日誌數據的存儲是另一大挑戰,日誌往往是海量的且往往價值不高,存儲成本成為用戶最顧慮的痛點之一。騰訊雲 ES 一方面通過壓縮編碼優化來降低單位文檔存儲成本,另一方面我們通過基於雲原生環境自研混合存儲方案,實現存儲與計算分離,降低存儲成本 50% 以上。
日誌數據的出口,查詢性能也是一大挑戰,海量數據場景下,大查詢對資源的開銷非常高,帶來的查詢延時也非常明顯。ES 原生支持了倒排索引,點查過濾的性能非常好,但無法滿足日誌場景大範圍查詢、聚合分析等性能需求。對此,騰訊雲 ES 進行了查詢裁剪、查詢並行化等一系列系統性優化,提升查詢性能數十倍。
下麵是日誌領域的挑戰總結,後面將針對高吞吐寫入、低成本存儲、高性能查詢層面的優化進行詳細分析。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406809-1224522977.png)
3. 高吞吐寫入
3.1 定向路由
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406611-2098217208.png)
ES 的一個 Bulk 寫入先進到協調節點(任意一個數據節點),會被拆分為若幹個分片粒度的子寫入請求,並分發給對應的數據節點。當集群規模較大,索引的分片數較多的場景下,分散式寫入的扇出放大非常嚴重,很容易受到個別長尾節點的 GC、慢盤、網路抖動等影響,導致寫入堆積,資源利用率低,拒絕率高。
騰訊雲 ES 內核通過引入寫入定向路由優化,將用戶的一個 Bulk 請求路由到一個分片數可控的分片組,降低寫入請求扇出影響,容忍慢節點,在不可靠的環境中提供可靠的服務。基於定向路由優化,某日誌業務場景,寫入吞吐提升一倍多,CPU 資源利用率提升 58%,拒絕率從 3% 降至 0。
定向路由解決了慢節點對寫入的影響,接下來我們看看如何優化寫入層面冗餘的計算開銷來提升性能。
3.2 物理複製
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406841-1698865515.png)
ES 單機引擎寫入,底層數據接收到可見分為三個步驟,如上圖所示。
-
數據在記憶體中構建各種數據類型,包括行存、列存、各種索引。 -
寫入 Translog,相當於 WAL 確保數據可靠性,機器掛掉數據可重放。 -
周期性 refresh 將記憶體中的數據結構 buffer 構建成完整的 segment 並打開 reader 可查。
ES 分散式層的寫入,數據先從協調節點轉發至 Primary,主分片寫完 Lucene 和 Translog 之後並行轉發給多個 Replica,副本分片完成 Lucene 和 Translog 的寫入。這個過程中,副本分片的 Lucene 寫入是冗餘的,因為這個寫入棧在 Primary 上進行了一遍,在 Replica 上會完整的再來一遍,開銷非常高。
物理複製解決的就是從分片上冗餘寫入棧的開銷。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406852-1857843790.png)
如上圖方案所示,第一步當 Primary 產生新的 Segment 之後,會及時通過物理拷貝方式同步至 Replica,使得 Segment 在 Replica 上可見,同時消除 Replica 上記憶體構建 Segment 過程的計算開銷。當 Primary 上產生新的 Commit 文件之後,也會及時同步至 Replica。同步 Commit 文件的目的主要是在 Replica 側清理過期的 Translog 和被合併的 Segment。例如在上面第三、四步中就描述了 Primary 側 Segment 合併之後同步到 Replica 側清理的過程。
通過 Segment 物理複製的能力,有效裁剪了 Replica 寫入的計算開銷,在主從副本場景下提升寫入性能接近一倍。
4. 低成本存儲
前面我們重點介紹了海量日誌數據高吞吐寫入層面的性能優化。海量的數據流入到 ES 之後,存儲是另一大挑戰,接下來我們來探討一下海量存儲場景如何進行成本優化,我們先來看看背景。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406600-1215114393.png)
存儲成本的影響面主要分為三個層面:
-
雲原生環境下分散式架構層。ES 的主從副本乘以底層雲盤、對象存儲等三份副本(EC 編碼優化推出可能在 1.33 左右)。 -
單機存儲引擎層。由於 ES 是行列混存,且有豐富的索引結構,應用場景豐富的同時,也導致了單位文檔存儲成本放大較多。 -
底層基礎設施。為了應對高吞吐寫入,往往需要引入 SSD 硬碟,其成本高壽命短。如果用冷熱架構,溫層往往會掛多塊 HDD 盤來擴大容量,此時單盤的損壞會導致整個節點替換,存在大量的數據恢復搬遷,代價太大。另外機器運維的人力成本也不低。
從上面幾個維度的成本影響面來看,我們的優化重點一方面是降低單位文檔的存儲成本,另一方面是降低冗餘副本、存儲介質的成本。
4.1 壓縮編碼優化
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406832-1461475140.png)
壓縮編碼優化是在原始數據結構不變的前提下,降低單位文檔存儲成本非常有效的方式。上圖中描述了 ES 底層 Lucene 的存儲格式,以及這些格式所用到的壓縮演算法。其中列存壓縮是由騰訊貢獻給社區的。
4.1.1 列存壓縮
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406880-1218358342.png)
Lucene 列存存儲分為兩部分,term dictionary 和 term ords,每個欄位值的原始內容存儲在 term dictionary 中,實際編碼、計算的時候為了避免冗餘而採用 term ords,後者會隨著新數據的持續寫入而動態更新。優化的主要內容是對 term dictionary 中的原始欄位字面內容進行壓縮存儲。從優化後的壓縮效果對比來看,寫入、merge 耗時基本不變的情況下,列存存儲下降了 40%+。
4.1.2 擴展基礎壓縮演算法
除了優化列存以外,我們還引入了新的通用壓縮演算法。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406627-296137549.png)
Zstandard 演算法在壓縮比上比 LZ4 更優,在性能上比 Deflate 更優,能相容兩者的優點。我們將該通用壓縮演算法引入到行存、列存、索引文件壓縮中,實測業務開啟 Zstandard 演算法之後,整體存儲成本下降 30%+。
4.2 混合存儲引擎
前面主要介紹了通過壓縮編碼優化降低單位文檔存儲成本,而單位文檔的存儲優化是有極限的。另一個方向是從存儲架構層面進行優化。在雲原生的背景下,我們引入了自研混合存儲引擎方案。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406956-1496743629.png)
混合存儲引擎的整體設計思路是基於典型的 delta + base 架構。其中 delta 部分我們採用 SSD,主要目的為了扛高併發寫入,以及小 segment 的存儲及合併;而 base 部分採用對象存儲,用於存儲大量不可變的大 segment,一方面其高可用(4 個 9 一個 5)、高可靠(12 個 9)、按量付費、免運維的架構降低了大量運維成本,更重要的是其提供的標準、低頻、歸檔等靈活的低成本存儲方案能大幅降低海量日誌的存儲成本。
接下來我們結合索引數據的生命周期看看混合存儲引擎的整體設計。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406888-2035659922.png)
混合存儲引擎整體分為兩層。上層存儲介質為 SSD,提供高併發的寫入能力,準實時產生的 segment 會通過物理複製的能力從 primary 拷貝至 replica。同時主從副本均寫入 translog,確保主從切換數據無縫對接及重啟數據不丟失,更重要的是主從副本之間的數據、segment 完全一致,這便於我們在 primary 上將數據下沉至底層共用存儲後,replica 可以無縫掛載查詢。每個分片本地都會有一個 RemoteDirectoryWrapper 封裝了對遠程共用存儲數據的訪問,包含了數據緩存的邏輯。底層共用存儲採用對象存儲,數據按照索引、分片粒度分目錄存儲,segment 數據文件一對一映射,方便存取。
下麵我們細分流程看看整體方案的設計細節。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406632-1094701821.png)
如上圖所示,前五個階段,主要是我們之前描述的物理複製的流程,主要目的是為了提升寫入性能,確保 primary 和 replica 數據保持完全一致,為後續的數據共用提供基礎。前面已描述詳細流程,這裡不展開分析。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406977-2132122629.png)
第六個階段,本地 segment 通過 merge 產生了較大的 segment,會被凍結不再參與 merge,並下沉至底層共用存儲。註意這個階段是從熱數據就開始的,並不是數據降溫後才啟動下沉,可以避免數據降溫後整體下沉的排隊擁塞,當然可以根據用戶的需求進行靈活配置。此時,日誌場景大量的查詢會集中在本地,本地 primary 和 replica 也能很好的抗住讀寫壓力。
第七個階段,數據的查詢頻次有所降低。一般情況,本地的 primary 即可滿足絕大部分查詢性能需求。此時 replica 會從本地卸載,讀取會走遠端共用存儲,同時本地會有緩存機制保存用戶常用查詢數據提升性能。此時的查詢會優先打到 primary。通過卸載本地 replica,我們可以縮減約 50% 的 SSD 容量。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406891-1267875308.png)
第八個階段,查詢頻率大幅縮減。Primary 上只有部分數據或部分 segment 需要被查詢,此時 primary 上的部分文件或 segment 會先被卸載。同時本地構建緩存體系加速查詢。本階段 SSD 的縮減達到 70% 左右,但仍然能滿足業務的查詢需求。
第九個階段,查詢幾乎沒有了,數據處於歸檔狀態。本地的 primary 徹底實現卸載,依靠本地的緩存加速滿足極少量的查詢需求。本階段 SSD 的縮減到達 90% 左右。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406629-1722644767.png)
在整個數據生命周期中,segment 呈現三種形態:
-
Local Segment。行列存、索引文件等全部在本地,抗住熱數據高併發讀寫請求。 -
Mixed Segment。行列存等數據文件可能卸載,只有部分索引文件在本地,滿足少量的查詢請求。 -
Remote Segment。行列存、索引文件等全部在遠程,本地只有少量元數據文件,滿足冷數據低成本歸檔需求。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406863-1787679176.png)
上面是完整的索引生命周期中數據的演變過程,存儲重心隨著數據逐漸降溫過程逐步從 SSD 到對象存儲遷移,且用戶無明顯感知,最終整體存儲成本下降 50% - 80%。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406888-529758913.png)
日誌場景傳統的降本方案一般採用冷熱分層。混合存儲引擎與冷熱分層主要的區別包括:
-
存儲架構差異。1). 傳統冷熱分層索引級別存儲介質固定。2). 混合存儲 SSD 和對象存儲是一個整體,數據可以雙向局部流通。 -
副本差異。1). 傳統冷熱分層存在冗餘副本。2). 混合存儲底層採用共用存儲,上層分片最終形態為邏輯分片,消除了雲原生環境下的冗餘副本。 -
數據搬遷差異。1). 傳統冷熱分層數據降溫後索引需要整體搬遷。2). 混合存儲支持在熱數據階段 segment 級別的數據下沉。 -
配置策略差異。1). 傳統冷熱分層依賴用戶的靜態配置策略,靈活性低、運維成本高。2). 混合存儲除了支持用戶配置外,還可根據用戶訪問統計信息自動決策數據下沉、卸載時機,實現數據智能分層。
截止目前日誌場景海量數據的低成本存儲優化到這裡就介紹完畢了,後面繼續介紹查詢性能優化。
5. 高性能查詢
5.1 查詢性能影響面
前面我們分析了日誌場景的海量存儲成本優化。數據存儲降本之後,接下來要考慮的是數據流出,如何解決用戶查詢性能問題。因為混合存儲底層採用對象存儲,其和 SSD 的性能差異肯定是有一個量級的區別。我們需要系統性做一些查詢優化、緩存優化來找回這種存儲介質的變更帶來的性能損耗。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406623-31535022.png)
我們先來看看混合存儲引擎背景下,查詢性能的瓶頸在哪些方面。
5.1.1 大量查詢空轉掃描
ES 有高效的倒排索引,點查的性能是非常強悍的。多索引或通過別名關聯索引查詢也是相對傳統資料庫的一個優勢特性,而這一特性也會帶來一些性能瓶頸問題。如上圖所示,當我們查詢的索引是一個星號,或者一個索引首碼匹配,或是一個別名的時候,底層可能關聯多個物理索引,而我們的查詢可能只有部分索引會有數據命中。而 ES 實際執行查詢會將底層所有匹配的索引、包括每個索引底層的每個分片逐一遍歷查詢。這樣會存在大量的無用索引、分片、segment 的查詢空轉掃描。
5.1.2 Segment 串列化執行
ES 底層分片之間是可以並行化的,但是單個分片內部多個 segment 之間是串列化的。混合存儲引擎的底層是對象存儲,多個 segment 串列化導致 IO 排隊嚴重,查詢效率低下,尤其是在大查詢拉取數據較多的場景下。
5.2 索引分片級時序裁剪優化
基於上面兩大影響面分析,我們針對性的優化思路是查詢裁剪和查詢並行化,下麵我們來展開分析。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406911-949166535.png)
在日誌場景,索引一般是按照一定的時間周期進行滾動,騰訊自研了自治索引,幫助用戶托管索引分片的管理,用戶無需關心底層分片的數量、大小、分佈配置。簡化數據接入門檻。在此基礎上,我們維護了索引級別的 Min/Max,當查詢請求進來的時候,可以針對用戶的查詢區間進行精準的物理索引過濾裁剪,大幅降低無用索引的空轉掃描過程。通過索引分片維度的時序裁剪,大幅提升查詢性能,內部視頻日誌業務實測查詢性能提升 8 倍。
5.3 Segment 級別查詢裁剪
單個分片包含多個 segment,在查詢過程中會依次遍歷 segment 進行查詢。但往往只有部分 segment 或者 segment 內部部分數據段存在有效數據,因此 segment 維度的查詢裁剪也是優化的重點。
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406932-1410974363.png)
Segment 級別查詢裁剪分為兩個維度:
-
Segment 整體裁剪。社區版本已經支持列存、數值索引等維度的裁剪,對 Terms 維度還缺少整體裁剪,騰訊進行了優化,並提交給了社區,點查性能提升 25.7%。 -
Segment 內數據裁剪。1). 流式聚合裁剪。在 Composite Aggregation 場景,支持聚合翻頁,每次翻頁會涉及大量重覆數據的查詢,騰訊進行了優化,基於 index sorting,每次翻頁採用起始 doc id 跳轉,加上滿足 size 條件提前結束優化,流式聚合性能提升 7 倍,且支持正、逆序,已反饋給社區。2). 時序裁剪。社區版本,在大的時序範圍查詢場景,構建實踐範圍 posting list 的時候,涉及大量的數據文件遍歷,產生大量的隨機 IO 影響查詢性能。TencentES OTeam 協作進行了深度優化,基於 index sorting,利用 BKD 做二級索引,實現端點提取裁剪遍歷,逆序採用二分查找,滿足了大範圍的時序查詢性能需求,時序搜索性能提升 40 倍。
5.4 Segment 並行化
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406629-1873619702.png)
原生 ES 單個分片內部多個 segment 查詢為串列化執行。Segment 並行化的思路主要是將多個 segment 的文檔進行統籌規劃,按照多線程切分,並行化查詢。對於做完 forcemerge 的場景也能很好的提高並行度。於此同時,我們在拉取底層共用存儲時,並不會整個文件拉回來,而是結合前面描述的數據裁剪能力,按照查詢需要拉取局部的數據段,大幅提升拉取效率。混合存儲引擎中,開啟並行化查詢優化相較原生版本查詢性能提升 5 倍。
6. 雲原生數據平臺
![圖片](https://img2023.cnblogs.com/blog/27422/202306/27422-20230615110406913-1052063658.png)
下一階段,騰訊雲 ES 將打造雲原生數據平臺,閉環 PB 級數據檢索、分析場景,全面覆蓋日誌場景低成本、高性能的需求。底層基於共用存儲,消除冗餘副本,實現存算分離架構,中間計算層會提供多種維度的集群,實現讀寫分離,檢索、分析場景分離等。上層提供各種免運維的數據服務,實現資源靈活調度,數據跨節點、跨邏輯集群掛載等。
目前騰訊雲推出的 Elasticsearch Serverless 服務已覆蓋上述大部分能力,後續會持續完善,敬請關註。
作者:daniel
本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/Elasticsearch-Core-Application-Scenario---Log-Optimization-Practice.html