內存吞金獸(Elasticsearch)的那些事兒 -- 常見問題痛點及解決方案


系列目錄

內存吞金獸(Elasticsearch)的那些事兒 -- 認識一下

內存吞金獸(Elasticsearch)的那些事兒 -- 數據結構及巧妙算法

內存吞金獸(Elasticsearch)的那些事兒 -- 架構&三高保證

內存吞金獸(Elasticsearch)的那些事兒 -- 寫入&檢索原理

內存吞金獸(Elasticsearch)的那些事兒 -- 常見問題痛點及解決方案

 

1、大數據量的查詢效率如何保證:

查詢的流程:往 ES 里寫的數據,實際上都寫到磁盤文件里去了,查詢的時候,操作系統會將磁盤文件里的數據自動緩存到 Filesystem Cache 里面去

 

最佳的情況下,就是機器的內存,至少可以容納總數據量的一半,僅僅在 es 中就存少量的數據,就是要用來搜索的那些索引,如果內存留給 filesystem cache 的是 100G,那么將索引數據控制在 100G 以內,這樣的話,數據幾乎全部走內存來搜索,性能非常之高,一般可以在 1 秒以內,但是生成環境的數據量往往還是會很多,有大致四種方案:

1)數據預熱

平時看的人很多的數據,每隔一會兒,去搜索一下熱數據,刷到 filesystem cache 里去,后面用戶實際上來看這個熱數據的時候,就是直接從內存里搜索了;

2)冷熱分離

將大量的訪問很少、頻率很低的數據,單獨寫一個索引,然后將訪問很頻繁的熱數據單獨寫一個索引。最好是將冷數據寫入一個索引中,然后熱數據寫入另外一個索引中,這樣可以確保熱數據在被預熱之后,盡量都讓他們留在 filesystem os cache 里,別讓冷數據給沖刷掉。

3)es+Hbase架構: 

es只存儲索引字段,其他數據放到mysql/hbase中;

舉例說明:id,name,age .... 30 個字段。現在搜索,只需要根據 id,name,age 三個字段來搜索。如果往 es 里寫入一行數據所有的字段,就會導致說 90% 的數據是不用來搜索的,結果硬是占據了 es 機器上的 filesystem cache 的空間,單條數據的數據量越大,就會導致 filesystem cahce 能緩存的數據就越少。其實,僅僅寫入 es 中要用來檢索的少數幾個字段就可以了,比如說就寫入es id,name,age 三個字段,然后你可以把其他的字段數據存在 mysql/hbase 里,我們一般是建議用 es + hbase 這么一個架構。

4)document 模型設計
對於 MySQL,我們經常有一些復雜的關聯查詢。es 里面的復雜的關聯查詢盡量別用,一旦用了性能一般都不太好。

要先在 Java 系統里就完成關聯,將關聯好的數據直接寫入 es 中。搜索的時候,就不需要利用 es 的搜索語法來完成 join 之類的關聯搜索了。

2、分頁查詢痛點及解決方案:

假設現在要查詢第100頁的10條數據,但是對於es來說,from=1000000,size=100,這時 es需要從各個分片上查詢出來10000100條數據,然后匯總計算后從其中取出100條。如果有5個分片則需要查詢出來5*10000100條數據,如果現在有並發的100個查詢請求,就會有50億左右的數據,占用的內存是非常高的,所以在使用es的分頁查詢過程中,剛開始翻頁可能速度比較快,可能到第一百頁查詢就需要4-5s,翻到1000頁以后,系統資源占用成指數級上升,很容易就會出現OOM直接報錯。

分頁方案:

1)基本的from-size查詢,es為了避免深度分頁帶來的內存開銷,from最大值設定到了10000,目前后台運營的翻頁最多關心近10頁的數據;

2)search after按照第一個檢索到的最后顯示的“balance”和‘_id’值,作為下一個檢索search_after的參數,例如假定size是10,當查詢990-1000時,通過上次傳遞的最后一個檢索到的值,在分片上就可以取到10條文檔,不支持上一頁查詢。

3)scroll查詢

scroll查詢原理是在第一次查詢的時候一次性生成一個快照,根據上一次的查詢的id來進行下一次的查詢,這個就類似於關系型數據庫的游標,然后每次滑動都是根據產生的游標id進行下一次查詢,這種性能比上面說的分頁性能要高出很多,基本都是毫秒級的。

注意點:scroll不支持跳頁查詢。

使用場景:對實時性要求不高的查詢。

代碼:

設置查詢條件

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        QueryBuilder builder = QueryBuilders.queryStringQuery( "123456" ).field( "code" );
        boolQueryBuilder.must(QueryBuilders.termQuery( "logType" "10" ))
                .must(builder);

首次查詢

  • 第一次查詢,跟平時的search查詢一樣需要設置index和type以及查詢條件。
  • 如果把查詢類型設置成SCAN,那么不能獲取結果並且不支持排序,只能獲得scrollId,如果使用默認設置或者不設置,那么第一次在獲取id的同時也可以獲取到查詢結果。
  • 這個size大小的意思不是總分頁的大小,實際數量應該是:所以實際返回的數量是:分片的數量*size
  • 滾動時間設置是指在這個查詢搜索結果的緩存時間,時間不能太久,畢竟內存空間是有限的。
SearchResponse response1 = client.prepareSearch( "_audit_0221" ).setTypes( "_log_0221" )
                     .setQuery(boolQueryBuilder)
                     .setSearchType(.setSearchType(SearchType.DEFAULT))
                     .setSize( 10 ).setScroll(TimeValue.timeValueMinutes( 5 ))
                     .addSort( "logTime" SortOrder.DESC)
                     .execute().actionGet(); //第一次查詢
for  (SearchHit searchHit : response1.getHits().hits()) {
             biz handle....;
}

第二次查詢

             for  (SearchHit searchHit : response1.getHits().hits()) {
             }
                     .execute().actionGet();
         }

4) 利用scroll-scan遍歷數據

使用場景:500w用戶,需要遍歷所有用戶發送數據,並且對順序沒有要求,這個時候我們可以使用scroll-scan。

查詢
  SearchResponse response = client.prepareSearch( "_audit_0221" ).setTypes( "_log_0221" )
                     .setQuery(boolQueryBuilder)
                     .setSearchType(SearchType.SCAN)
                     .setSize( 5 ).setScroll(TimeValue.timeValueMinutes( 5 ))
                     .addSort( "logTime" SortOrder.DESC)
                     .execute().actionGet();
獲取結果
                 .execute().actionGet();
 
             for  (SearchHit searchHit : response1.getHits().hits()) {
             }
                     .execute().actionGet();
}


scroll和scroll-scan區別

  1. scroll支持排序,scroll-scan不支持排序,是按照索引順序返回,可以提高查詢效率。

  2. scroll-scan第一次查詢只支持返回id,沒有結果。

總結:

    1. es的分頁查詢不支持深度分頁,如果偏要使用要結合具體業務場景進行使用。不能當成關系型數據庫中的分頁進行使用。
    2. 要想提高產品體驗和查詢效率不能過於依賴技術,要結合需求進行分析以提高體驗,因為很多搜索類產品都不支持深度分頁。
    3. 如果在不涉及排序的情況下盡量使用scroll-scan,它是按照索引順序返回,提高效率。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM