您好,登錄后才能下訂單哦!
ElasticSearch中怎么提高查詢效率,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
你往 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% 的人在訪問熱數據,也無所謂了。
對于 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 做分頁的時候,你會發現越翻到后面,就越是慢。
類似于微博中,下拉刷微博,刷出來一頁一頁的,你可以用 scroll api
,關于如何使用,自行上網搜索。
scroll 會一次性給你生成所有數據的一個快照,然后每次滑動向后翻頁就是通過游標 scroll_id
移動,獲取下一頁下一頁這樣子,性能會比上面說的那種分頁性能要高很多很多,基本上都是毫秒級的。
但是,唯一的一點就是,這個適合于那種類似微博下拉翻頁的,不能隨意跳到任何一頁的場景。也就是說,你不能先進入第 10 頁,然后去第 120 頁,然后又回到第 58 頁,不能隨意亂跳頁。所以現在很多產品,都是不允許你隨意翻頁的,app,也有一些網站,做的就是你只能往下拉,一頁一頁的翻。
初始化時必須指定 scroll
參數,告訴 es 要保存此次搜索的上下文多長時間。你需要確保用戶不會持續不斷翻頁翻幾個小時,否則可能因為超時而失敗。
除了用 scroll api
,你也可以用 search_after
來做,search_after
的思想是使用前一頁的結果來幫助檢索下一頁的數據,顯然,這種方式也不允許你隨意翻頁,你只能一頁頁往后翻。初始化時,需要使用一個唯一值的字段作為 sort 字段。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。