Elasticsearch如何做到億級資料查詢毫秒級返回?
如果面試的時候碰到這樣一個面試題:ES 在資料量很大的情況下(數十億級別)如何提高查詢效率?
這個問題說白了,就是看你有沒有實際用過 ES,因為啥?其實 ES 效能並沒有你想象中那麼好的。
很多時候資料量大了,特別是有幾億條資料的時候,可能你會懵逼的發現,跑個搜尋怎麼一下 5~10s,坑爹了。
第一次搜尋的時候,是 5~10s,後面反而就快了,可能就幾百毫秒。
你就很懵,每個使用者第一次訪問都會比較慢,比較卡麼?所以你要是沒玩兒過 ES,或者就是自己玩玩兒 Demo,被問到這個問題容易懵逼,顯示出你對 ES 確實玩的不怎麼樣?
說實話,ES 效能優化是沒有銀彈的。啥意思呢?就是不要期待著隨手調一個引數,就可以萬能的應對所有的效能慢的場景。
也許有的場景是你換個引數,或者調整一下語法,就可以搞定,但是絕對不是所有場景都可以這樣。
效能優化的殺手鐗:Filesystem Cache
你往 ES 裡寫的資料,實際上都寫到磁碟檔案裡去了,查詢的時候,作業系統會將磁碟檔案裡的資料自動快取到 Filesystem Cache 裡面去。
ES 的搜尋引擎嚴重依賴於底層的 Filesystem Cache,你如果給 Filesystem Cache 更多的記憶體,儘量讓記憶體可以容納所有的 IDX Segment File 索引資料檔案,那麼你搜尋的時候就基本都是走記憶體的,效能會非常高。
效能差距究竟可以有多大?我們之前很多的測試和壓測,如果走磁碟一般肯定上秒,搜尋效能絕對是秒級別的,1 秒、5 秒、10 秒。
但如果是走 Filesystem Cache,是走純記憶體的,那麼一般來說效能比走磁碟要高一個數量級,基本上就是毫秒級的,從幾毫秒到幾百毫秒不等。
這裡有個真實的案例:某個公司 ES 節點有 3 臺機器,每臺機器看起來記憶體很多 64G,總記憶體就是 64 * 3 = 192G。
每臺機器給 ES JVM Heap 是 32G,那麼剩下來留給 Filesystem Cache 的就是每臺機器才 32G,總共叢集裡給 Filesystem Cache 的就是 32 * 3 = 96G 記憶體。
而此時,整個磁碟上索引資料檔案,在 3 臺機器上一共佔用了 1T 的磁碟容量,ES 資料量是 1T,那麼每臺機器的資料量是 300G。這樣效能好嗎?
Filesystem Cache 的記憶體才 100G,十分之一的資料可以放記憶體,其他的都在磁碟,然後你執行搜尋操作,大部分操作都是走磁碟,效能肯定差。
歸根結底,你要讓 ES 效能好,最佳的情況下,就是你的機器的記憶體,至少可以容納你的總資料量的一半。
根據我們自己的生產環境實踐經驗,最佳的情況下,是僅僅在 ES 中就存少量的資料,就是你要用來搜尋的那些索引,如果記憶體留給 Filesystem Cache 的是 100G,那麼你就將索引資料控制在 100G 以內。
這樣的話,你的資料幾乎全部走記憶體來搜尋,效能非常之高,一般可以在1秒以內。
比如說你現在有一行資料:id,name,age .... 30 個欄位。但是你現在搜尋,只需要根據 id,name,age 三個欄位來搜尋。
如果你傻乎乎往 ES 裡寫入一行資料所有的欄位,就會導致說 90% 的資料是不用來搜尋的。
結果硬是佔據了 ES 機器上的 Filesystem Cache 的空間,單條資料的資料量越大,就會導致 Filesystem Cahce 能快取的資料就越少。
其實,僅僅寫入 ES 中要用來檢索的少數幾個欄位就可以了,比如說就寫入 es id,name,age 三個欄位。
然後你可以把其他的欄位資料存在 MySQL/HBase 裡,我們一般是建議用 ES + HBase 這麼一個架構。
HBase 的特點是適用於海量資料的線上儲存,就是對 HBase 可以寫入海量資料,但是不要做複雜的搜尋,做很簡單的一些根據 id 或者範圍進行查詢的這麼一個操作就可以了。
從 ES 中根據 name 和 age 去搜尋,拿到的結果可能就 20 個 doc id,然後根據 doc id 到 HBase 裡去查詢每個 doc id 對應的完整的資料,給查出來,再返回給前端。
寫入 ES 的資料最好小於等於,或者是略微大於 ES 的 Filesystem Cache 的記憶體容量。
然後你從 ES 檢索可能就花費 20ms,然後再根據 ES 返回的 id 去 HBase 裡查詢,查 20 條資料,可能也就耗費個 30ms。
可能你原來那麼玩兒,1T 資料都放 ES,會每次查詢都是 5~10s,現在可能效能就會很高,每次查詢就是 50ms。
資料預熱
假如說,哪怕是你就按照上述的方案去做了,ES 叢集中每個機器寫入的資料量還是超過了 Filesystem Cache 一倍。
比如說你寫入一臺機器 60G 資料,結果 Filesystem Cache 就 30G,還是有 30G 資料留在了磁碟上。
其實可以做資料預熱。舉個例子,拿微博來說,你可以把一些大 V,平時看的人很多的資料,提前在後臺搞個系統。
每隔一會兒,自己的後臺系統去搜尋一下熱資料,刷到 Filesystem Cache 裡去,後面使用者實際上來看這個熱資料的時候,他們就是直接從記憶體裡搜尋了,很快。
或者是電商,你可以將平時檢視最多的一些商品,比如說 iPhone 8,熱資料提前後臺搞個程式,每隔 1 分鐘自己主動訪問一次,刷到 Filesystem Cache 裡去。
對於那些你覺得比較熱的、經常會有人訪問的資料,最好做一個專門的快取預熱子系統。
就是對熱資料每隔一段時間,就提前訪問一下,讓資料進入 Filesystem Cache 裡面去。這樣下次別人訪問的時候,效能一定會好很多。
冷熱分離
ES 可以做類似於 MySQL 的水平拆分,就是說將大量的訪問很少、頻率很低的資料,單獨寫一個索引,然後將訪問很頻繁的熱資料單獨寫一個索引。
最好是將冷資料寫入一個索引中,然後熱資料寫入另外一個索引中,這樣可以確保熱資料在被預熱之後,儘量都讓他們留在 Filesystem OS Cache 裡,別讓冷資料給沖刷掉。
你看,假設你有 6 臺機器,2 個索引,一個放冷資料,一個放熱資料,每個索引 3 個 Shard。3 臺機器放熱資料 Index,另外 3 臺機器放冷資料 Index。
這樣的話,你大量的時間是在訪問熱資料 Index,熱資料可能就佔總資料量的 10%,此時資料量很少,幾乎全都保留在 Filesystem Cache 裡面了,就可以確保熱資料的訪問效能是很高的。
但是對於冷資料而言,是在別的 Index 裡的,跟熱資料 Index 不在相同的機器上,大家互相之間都沒什麼聯絡了。
如果有人訪問冷資料,可能大量資料是在磁碟上的,此時效能差點,就 10% 的人去訪問冷資料,90% 的人在訪問熱資料,也無所謂了。
Document 模型設計
對於 MySQL,我們經常有一些複雜的關聯查詢。在 ES 裡該怎麼玩兒,ES 裡面的複雜的關聯查詢儘量別用,一旦用了效能一般都不太好。
最好是先在 Java 系統裡就完成關聯,將關聯好的資料直接寫入 ES 中。搜尋的時候,就不需要利用 ES 的搜尋語法來完成 Join 之類的關聯搜尋了。
Document 模型設計是非常重要的,很多操作,不要在搜尋的時候才想去執行各種複雜的亂七八糟的操作。
ES 能支援的操作就那麼多,不要考慮用 ES 做一些它不好操作的事情。如果真的有那種操作,儘量在 Document 模型設計的時候,寫入的時候就完成。
另外對於一些太複雜的操作,比如 join/nested/parent-child 搜尋都要儘量避免,效能都很差的。
分頁效能設計
ES 的分頁是較坑的,為啥呢?舉個例子吧,假如你每頁是 10 條資料,你現在要查詢第 100 頁,實際上是會把每個 Shard 上儲存的前 1000 條資料都查到一個協調節點上。
如果你有 5 個 Shard,那麼就有 5000 條資料,接著協調節點對這 5000 條資料進行一些合併、處理,再獲取到最終第 100 頁的 10 條資料。
分散式的,你要查第 100 頁的 10 條資料,不可能說從 5 個 Shard,每個 Shard 就查 2 條資料,最後到協調節點合併成 10 條資料吧?
你必須得從每個 Shard 都查 1000 條資料過來,然後根據你的需求進行排序、篩選等等操作,最後再次分頁,拿到裡面第 100 頁的資料。
你翻頁的時候,翻的越深,每個 Shard 返回的資料就越多,而且協調節點處理的時間越長,非常坑爹。所以用 ES 做分頁的時候,你會發現越翻到後面,就越是慢。
我們之前也是遇到過這個問題,用 ES 作分頁,前幾頁就幾十毫秒,翻到 10 頁或者幾十頁的時候,基本上就要 5~10 秒才能查出來一頁資料了。
有什麼解決方案嗎?不允許深度分頁(預設深度分頁效能很差)。跟產品經理說,你係統不允許翻那麼深的頁,預設翻的越深,效能就越差。
類似於 App 裡的推薦商品不斷下拉出來一頁一頁的;類似於微博中,下拉刷微博,刷出來一頁一頁的,你可以用 Scroll API,關於如何使用,自行上網搜尋。
Scroll 會一次性給你生成所有資料的一個快照,然後每次滑動向後翻頁就是通過遊標 scroll_id 移動,獲取下一頁、下一頁這樣子,效能會比上面說的那種分頁效能要高很多很多,基本上都是毫秒級的。
但是,唯一的一點就是,這個適合於那種類似微博下拉翻頁的,不能隨意跳到任何一頁的場景。
也就是說,你不能先進入第 10 頁,然後去第 120 頁,然後又回到第 58 頁,不能隨意亂跳頁。
所以現在很多產品,都是不允許你隨意翻頁的,App,也有一些網站,做的就是你只能往下拉,一頁一頁的翻。
初始化時必須指定 Scroll 引數,告訴 ES 要儲存此次搜尋的上下文多長時間。你需要確保使用者不會持續不斷翻頁翻幾個小時,否則可能因為超時而失敗。
除了用 Scroll API,你也可以用 search_after 來做。search_after 的思想是使用前一頁的結果來幫助檢索下一頁的資料。
顯然,這種方式也不允許你隨意翻頁,你只能一頁頁往後翻。初始化時,需要使用一個唯一值的欄位作為 Sort 欄位。
出處:https://zhuanlan.zhihu.com/p/60458049
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556440/viewspace-2646392/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 1.3萬億條資料查詢如何做到毫秒級響應?
- mysql 如何毫秒級同步資料到 elasticsearchMySqlElasticsearch
- ElasticSearch在數十億級別資料下,如何提高查詢效率?Elasticsearch
- 上億級別資料庫查詢資料庫
- 百億資料,毫秒級返回,如何設計?--淺談實時索引構建之道索引
- mongodb索引--1億條記錄的查詢從55.7秒到毫秒級別MongoDB索引
- 毫秒間查詢千億級Trace資料,SkyWalking上鍊路追蹤這麼強?
- 少即是多:從分鐘級提升到毫秒級的PostgreSQL查詢SQL
- Elasticsearch從0到千萬級資料查詢實踐(非轉載)Elasticsearch
- ElasticSearch 億級資料檢索案例實戰Elasticsearch
- 毫秒級從百億大表任意維度篩選資料,是怎麼做到的...
- 毫秒級查詢的離線IP地址定位庫,太實用了!
- PB級資料實時查詢,滴滴Elasticsearch多叢集架構實踐Elasticsearch架構
- elasticsearch查詢之大資料集分頁查詢Elasticsearch大資料
- NFTScan x TiDB丨一棧式 HTAP 資料庫為 Web3 資料服務提供毫秒級多維查詢TiDB資料庫Web
- 全國快遞物流查詢API,毫秒級響應、超高及時性API
- ElasticSearch第4篇(億級中文資料量 ElasticSearch與Sphinx建索引速度、查詢速度、併發效能、實測對比)Elasticsearch索引
- 毫秒級返回資料,58同城 DBA 團隊選擇 TDengine 解決感測器資料處理難題
- 【ElasticSearch】給ElasticSearch資料庫配置慢查詢日誌Elasticsearch資料庫
- AppBoxFuture: 二級索引及索引掃描查詢資料APP索引
- MyBatis千萬級資料查詢解決方案,避免OOMMyBatisOOM
- QL Server 百萬級資料提高查詢速度的方法Server
- Elasticsearch 億級資料檢索效能最佳化案例實戰!Elasticsearch
- 如何實現引數級聯查詢
- 使用cglib實現資料庫框架的級聯查詢CGLib資料庫框架
- 百億級資料分表後怎麼分頁查詢?
- [Python]_[初級]_[校驗查詢sqlite3資料庫]PythonSQLite資料庫
- Elasticsearch 8.X 如何生成 TB 級的測試資料 ?Elasticsearch
- MySQL 億級資料資料庫最佳化方案測試-銀行交易流水記錄的查詢MySql資料庫
- Elasticsearch查詢Elasticsearch
- 炸!億級資料DB秒級平滑擴容!!!
- elasticsearch查詢之大資料集分頁效能分析Elasticsearch大資料
- .NetCore下ES查詢驅動 PlainElastic .Net 升級官方驅動 Elasticsearch .NetNetCoreAIElasticsearch
- 如何使用PL/SQL進行分級查詢WPSQL
- 易倉跨境Saas全球租戶,如何做到資料秒級響應?
- ES 20 - 查詢Elasticsearch中的資料 (基於DSL查詢, 包括查詢校驗match + bool + term)Elasticsearch
- Elasticsearch複合查詢——boosting查詢Elasticsearch
- 【實戰】利用多執行緒優化查詢百萬級資料執行緒優化