京東 ES 支援 ZSTD 壓縮演算法上線了,這是一種高效能、低成本的壓縮演算法,能夠提高資料儲存和傳輸的效率,同時降低儲存和頻寬成本。ZSTD 演算法是一種快速壓縮演算法,可提供比其他壓縮演算法更高的壓縮比和更快的壓縮速度。這意味著,京東 ES 使用者可以更高效地儲存和傳輸資料,同時節省儲存和頻寬成本。此外,ZSTD 演算法還具有更好的可擴充套件性和魯棒性,可滿足大規模分散式系統的需求。因此,京東 ES 支援 ZSTD 壓縮演算法上線,將為使用者帶來更高的效能、更低的成本和更好的體驗。
01 前言
在今年的敏捷團隊建設中,我透過 Suite 執行器實現了一鍵自動化單元測試。Juint 除了 Suite 執行器還有哪些執行器呢?由此我的 Runner 探索之旅開始了!
在 2022 年 10 月份《ElasticSearch 降本增效常見的方法》一文中曾提到過 zstd 壓縮演算法 [1],一步一個腳印,我們終於在京東 ES 上線支援了 zstd;我覺得促使目標完成主要以下幾點原因:
1.Elastic 官方原因:zstd 壓縮演算法沒有在 Elastic 官方的開發計劃中;Elastic 的 licenes 變更,很多功能使用受限
2.ES 產品競爭力:提升京東 ES 產品在業界的競爭力,兩大雲友商和其他大廠都在陸續支援,在對外比拼的時候,我們需要提升我們這方面的能力
- 信創大背景:我們需要對開源元件有更好的自主管控和建設能力
- 京東零售 ES 與雲 ES 產品融合:有更好的機會去打磨我們的 ES 核心
- 降本增效:ztsd 壓縮演算法,能夠在降低儲存成本的前提下,保證效能幾乎不受損,寫入效能還有所提升
02 測試結果
測試叢集配置:4c8g; 3 個資料節點;
測試索引設定:3 主分片 1 副本
測試資料 mapping: keyword 欄位 14 個,geo_point 欄位 3 個,integer 欄位 2 個,text 欄位 1 個,date 欄位:2 個,ip 型別欄位 1 個,boolean 欄位 1 個
在考慮到讀寫效能和壓縮比均衡的情況下,我們推薦使用 jd_zstd (壓縮等級 3):
jd_zstd (壓縮等級 3) 寫入效能相對於 best_compression 提升 38.46%,相對於 lz 提升 5.88%;
jd_zstd (壓縮等級 3) 儲存相對於 lz4 節省 24%,與 best_compression 基本持平,單位寫的 gb 實際是要比 best_compression 的儲存量小。
下表為 es6.8.23 版本,在 cpu 壓測到 100% 時,不通壓縮演算法下 ES 的 bulk、termquery、rangequery、matchquery 等 TPS 以及壓縮比測試結果:
注意⚠️:測試資料僅供參考,實際情況與使用者資料有關
03 適用場景
寫多讀少的場景,比如日誌和監控場景。
04 使用方法
雲上 ES 等待上線後,可以進行申請
目前我們暫時只在內部泰山零售 ES 上線,支援 7.X 和 6.8.23 版本;後續會在雲艦 ES 和公有云 ES 上線,由於 licenes 的限制,我們將只推出 6.8.23 版本。
Q1: 如何申請?
A1: 內部使用者:之前在泰山平臺申請的傑斯 ES,如果使用的是 7.X 和 6.8.23,可以選擇版本升級到最新版本。新建叢集,直接提工單申請
Q2 ztsd 如何使用?
A2: 我們在 ES 中支援兩種 zstd 壓縮等級,使用者可以根據自己的業務和資料特性選擇合適的壓縮等級;ES 建立索引時指定 index.codec:jd_zstd(壓縮等級為 3)或者 jd_zstd_6(壓縮等級為 6) 即可,其餘沒有其他任何特殊之處。
注意⚠️:index.codec 的壓縮演算法不支援動態修改,必須建立索引時設定好。
建立索引zstdtest 壓縮等級為 3
PUT zstdtest
{
“settings”: {
“index”: {
“codec”: “jd_zstd”
}
}
}
建立索引zstdtest_6 壓縮等級為 3
PUT zstdtest_6
{
“settings”: {
“index”: {
“codec”: “jd_zstd_6”
}
}
}
05 技術實現
首先我們介紹下 ES 與 Lucene 的關係;如下圖所示,在叢集層面:一個 ES 叢集由多個節點組成。資料層面:1 個索引是由多個分片組成的,一個分片可以看是一個 Lucene 例項;一個分片包含多個 segement,一個 segement 即一組資料的最小單元,包含很多的資料檔案。
1.Lucene 檔案
lucene [2] 的資料檔案主要由以下檔案組成:
上述的檔案大致可以分為以下幾類:
行存相關檔案:主要包括原文儲存檔案.fdt 和原文索引檔案.fdx。使用者寫入的原始資料都被儲存於.fdt,佔比是最大的,Lucene 在原文儲存上支援 LZ4 和 ZIP (best_compression) 壓縮。在寫入資料時,ES 把 doc 原始資料的整個 json 結構體當做一個 string,儲存為_source 欄位,因此原文儲存檔案.fdt 中_source 欄位佔比最大;部分場景為了節省磁碟儲存,直接將該欄位關閉,資料查詢時仍可透過 ES 的 docvalue_fields 獲取所有欄位的值;
“_source”: {
“enabled”: false
}
注意⚠️:關閉_source 後, update, update_by_query, reindex 等功能無法正常使用,因此有 update 等需求的索引不能關閉_source.
列存相關檔案:.dvd 檔案,常用於 OLAP 分析,ES 使用列存來支援 sorting, aggregations 和 scripts 功能。不同文件 Document 中的同一列 (Field) 資料相鄰存放,加速列聚合分析性查詢。相鄰每列型別相同,在儲存的時候可以進行統一性的編碼最佳化,提高壓縮率,減少儲存磁碟空間的佔用。ES 中欄位使用 doc_values 字為 true,即為開啟列儲存。
索引相關檔案:主要檔案包括字典資料檔案.tim 和倒排索引.doc 檔案。ES 依靠分詞器產生倒排索引,從而具備強大的全文檢索能力。索引配置分詞器後,將從攝入文件資料中提取分詞資訊並儲存於.tim 檔案。同一列的分詞資訊相鄰存放,按塊組織;.doc 檔案也被稱為 “倒排拉鍊表”,記錄每一個詞項所關聯的文件 id 列表,實現詞項到文件的快速倒排查詢。倒排索引也會進行壓縮,其壓縮演算法主要有 Frame Of Reference、Roaring Bitmap 和 fst 等。
向量資料檔案:向量索引 tvx 和向量資料.tvd 檔案,支援以圖搜圖,和音訊的查詢等。透過對攝入實體進行向量化,然後使用向量搜尋演算法進行檢索。相關向量搜尋演算法有 HNSW [3],近似向量搜尋 knn [4];elastic 公司在今年 5 月份左右推出用於人工智慧的 Elasticsearch 相關性引擎 ESRE [5]。
zstd 主要壓縮為行儲存相關檔案.fdm、.fdt 和.fdx;如下程式碼塊為壓縮檔案對比,可以看出在不同的壓縮演算法中,這幾個檔案的大小是不同的。
為了節省篇幅部分檔案省略
lz4壓縮演算法索引testlz4 0 號分片
total 2.4G
-rw-r–r-- 1 admin admin 1.2K Nov 16 16:19 _32.fdm
-rw-r–r-- 1 admin admin 1.3G Nov 16 16:19 _32.fdt
-rw-r–r-- 1 admin admin 76K Nov 16 16:19 _32.fdx
-rw-r–r-- 1 admin admin 85M Nov 16 16:21 _32.kdd
-rw-r–r-- 1 admin admin 149M Nov 16 16:21 _32_Lucene80_0.dvd
…
-rw-r–r-- 1 admin admin 401 Nov 16 16:21 segments_b
-rw-r–r-- 1 admin admin 0 Oct 16 16:05 write.lock
best_compression壓縮演算法索引 testbestcompression 0 號分片
total 1.9G
-rw-r–r-- 1 admin admin 287 Nov 16 17:01 _2b.fdm
-rw-r–r-- 1 admin admin 781M Nov 16 17:01 _2b.fdt
-rw-r–r-- 1 admin admin 17K Nov 16 17:01 _2b.fdx
-rw-r–r-- 1 admin admin 85M Nov 16 17:03 _2b.kdd
-rw-r–r-- 1 admin admin 148M Nov 16 17:03 _2b_Lucene80_0.dvd
…
-rw-r–r-- 1 admin admin 401 Nov 16 17:03 segments_a
-rw-r–r-- 1 admin admin 0 Oct 16 16:27 write.lock
zstd壓縮等級為3 索引testzstd3 0 號分片
total 1.9G
-rw-r–r-- 1 admin admin 286 Nov 16 17:26 _8e.fdm
-rw-r–r-- 1 admin admin 758M Nov 16 17:26 _8e.fdt
-rw-r–r-- 1 admin admin 15K Nov 16 17:26 _8e.fdx
-rw-r–r-- 1 admin admin 84M Nov 16 17:29 _8e.kdd
-rw-r–r-- 1 admin admin 148M Nov 16 17:29 _8e_Lucene80_0.dvd
-rw-r–r-- 1 admin admin 3.5K Nov 16 17:29
…
-rw-r–r-- 1 admin admin 402 Nov 16 17:29 segments_9
-rw-r–r-- 1 admin admin 0 Nov 15 16:50 write.lock
zstd壓縮等級為6 索引testzstd6 0 號分片
total 1.9G
-rw-r–r-- 1 admin admin 286 Nov 16 16:56 _29.fdm
-rw-r–r-- 1 admin admin 742M Nov 16 16:56 _29.fdt
-rw-r–r-- 1 admin admin 9.8K Nov 16 16:56 _29.fdx
-rw-r–r-- 1 admin admin 86M Nov 16 16:58 _29.kdd
-rw-r–r-- 1 admin admin 148M Nov 16 16:58 _29_Lucene80_0.dvd
…
-rw-r–r-- 1 admin admin 412 Nov 16 16:58 segments_a
-rw-r–r-- 1 admin admin 0 Oct 16 16:04 write.lock
zstd壓縮等級為9 索引testzstd9 0 號分片
total 1.9G
-rw-r–r-- 1 admin admin 286 Nov 16 17:21 _gp.fdm
-rw-r–r-- 1 admin admin 738M Nov 16 17:21 _gp.fdt
-rw-r–r-- 1 admin admin 13K Nov 16 17:21 _gp.fdx
-rw-r–r-- 1 admin admin 85M Nov 16 17:23 _gp.kdd
-rw-r–r-- 1 admin admin 149M Nov 16 17:23 _gp_Lucene80_0.dvd
…
-rw-r–r-- 1 admin admin 402 Nov 16 17:23 segments_8
-rw-r–r-- 1 admin admin 0 Nov 15 16:50 write.lock
2.ES 側實現
理論上來說 index.codec 支援的壓縮演算法最好下沉到 lucene 程式碼中,目前我們並沒有維護 lucene 程式碼,因此我們直接 ES 側面程式碼實現。zstd [1] 演算法是基於 C++ 實現,而 ES 是基於 java 編寫,因此藉助開源的力量,引入 zstd-jni 來實現 zstd 壓縮能力。
zstd_jni版本 1.5.5-1
api “com.github.luben:zstd-jni:${versions.zstd_jni}”
在 ES 程式碼中編寫自定義的 index.codec; 擴充套件 CompressionMode 壓縮模式,自定義實現 ZstdCompressor 壓縮和 ZstdDecompressor 解壓縮方法,可以在這設定 zstd 的壓縮等級以及控制讀寫資料塊大小;最後透過 java 的 spl 機制實現載入我們自定義的壓縮演算法實現類
在 server/src/main/resources/META-INF/services/org.apache.lucene.codecs.Codec 檔案中定義如下。
org.elasticsearch.index.codec.custom.ZstdCodec
注意⚠️:由於 ES 節點啟動的時候,有 security 檢查機制,因此我們需要在 server/src/main/resources/org/elasticsearch/bootstrap/security.policy 檔案中新增程式碼許可權授權策略
grant codeBase “${codebase.zstd-jni}” {
permission java.lang.RuntimePermission “loadLibrary. ";
permission java.lang.RuntimePermission "libzstd. ”;
};