Elasticsearch索引和查詢性能調優的21條建議【下】

Elasticsearch是一款流行的分佈式開源搜索和數據分析引擎,具備高性能、易擴展、容錯性強等特點。它強化了Apache Lucene的搜索能力,把掌控海量數據索引和查詢的方式提升到一個新的層次。

本文結合開源社區和阿里雲平臺的實踐經驗,探討如何調優Elasticsearch的性能,提高索引和查詢吞吐量。

/ 前文回顧 /

Elasticsearch索引和查詢性能調優的21條建議【上】

點擊查看大圖

查詢性能調優建議

01

使用過濾器緩存和分片查詢緩存

默認情況下,Elasticsearch的查詢會計算返回的每條數據與查詢語句的相關度,但對於非全文索引的使用場景,用戶並不關心查詢結果與查詢條件的相關度,只是想精確地查找目標數據。此時,可以通過filter來讓Elasticsearch不計算評分,並且儘可能地緩存filter的結果集,供後續包含相同filter的查詢使用,提高查詢效率。

普通查詢

curl -XGET "http://localhost:9200/twitter/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "user": "kimchy"
    }
  }
}'

過濾器(filter)查詢

curl -XGET "http://localhost:9200/twitter/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": {
         "match": {
          "user": "kimchy"
        }
      }
    }
  }
}'

分片查詢緩存的目的是緩存聚合、提示詞結果和命中數(它不會緩存返回的文檔,因此,它只在search_type=count時起作用)。

通過下面的參數我們可以設置分片緩存的大小,默認情況下是JVM堆的1%大小,當然我們也可以手動設置在config/elasticsearch.yml文件裏:

indices.requests.cache.size: 1%

查看緩存佔用內存情況

(name表示節點名, query_cache表示過濾器緩存,request_cache表示分片緩存,fielddata表示字段數據緩存,segments表示索引段)

curl -XGET "http://localhost:9200/_cat/nodes?h=name,query_cache.memory_size,request_cache.memory_size,fielddata.memory_size,segments.memory&v" 

02

使用路由routing

Elasticsearch寫入文檔時,文檔會通過一個公式路由到一個索引中的一個分片上。默認的公式如下:

shard_num = hash(_routing) % num_primary_shards

_routing字段的取值,默認是_id字段,可以根據業務場景設置經常查詢的字段作爲路由字段。例如可以考慮將用戶id、地區作爲路由字段,查詢時可以過濾不必要的分片,加快查詢速度。

寫入時指定路由

curl -XPUT "http://localhost:9200/my_index/my_type/1?routing=user1" -H 'Content-Type: application/json' -d'
{
  "title": "This is a document",
  "author": "user1"
}'

查詢時不指定路由,需要查詢所有分片

curl -XGET "http://localhost:9200/my_index/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}'

返回結果

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  }
  ......
}

查詢時指定路由,只需要查詢1個分片

curl -XGET "http://localhost:9200/my_index/_search?routing=user1" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}'

返回結果

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  }
  ......
}

03

強制合併只讀索引

關閉歷史數據索引

只讀索引可以從合併成一個單獨的大segment中收益,減少索引碎片,減少JVM堆常駐內存。強制合併索引操作會耗費大量磁盤IO,儘量配置在業務低峯期(例如凌晨)執行。歷史數據索引如果業務上不再支持查詢請求,可以考慮關閉索引,減少JVM內存佔用。

索引forcemerge API

curl -XPOST "http://localhost:9200/abc20180923/_forcemerge?max_num_segments=1"

索引關閉API

curl -XPOST "http://localhost:9200/abc2017*/_close"

04

配置合適的分詞器

Elasticsearch內置了很多分詞器,包括standard、cjk、nGram等,也可以安裝自研/開源分詞器。根據業務場景選擇合適的分詞器,避免全部採用默認standard分詞器。

常用分詞器:

  • standard:默認分詞,英文按空格切分,中文按照單個漢字切分。

  • cjk:根據二元索引對中日韓文分詞,可以保證查全率。

  • nGram:可以將英文按照字母切分,結合ES的短語搜索(match_phrase)使用。

  • IK:比較熱門的中文分詞,能按照中文語義切分,可以自定義詞典。

  • pinyin:可以讓用戶輸入拼音,就能查找到相關的關鍵詞。

  • aliws:阿里巴巴自研分詞,支持多種模型和分詞算法,詞庫豐富,分詞結果準確,適用於電商等對查準要求高的場景。

分詞效果測試API

curl -XPOST "http://localhost:9200/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer": "ik_max_word",
  "text":     "南京市長江大橋"
}'

常用中文分詞器效果對比

05

配置查詢聚合節點

查詢聚合節點可以發送粒子查詢請求到其他節點,收集和合並結果,以及響應發出查詢的客戶端。通過給查詢聚合節點配置更高規格的CPU和內存,可以加快查詢運算速度、提升緩存命中率。

某客戶使用25臺8核CPU32G內存節點Elasticsearch集羣,查詢QPS在4000左右。增加6臺16核CPU32G內存節點作爲查詢聚合節點,觀察服務器CPU、JVM堆內存使用情況,並調整緩存、分片、副本參數,查詢QPS達到12000。

# 查詢聚合節點配置(conf/elasticsearch.yml):


node.master:false
node.data:false
node.ingest:false

06

設置查詢讀取記錄條數和字段

默認的查詢請求通常返回排序後的前10條記錄,最多一次讀取10000條記錄,通過from和size參數控制讀取記錄範圍,避免一次讀取過多的記錄。通過_source參數可以控制返回字段信息,儘量避免讀取大字段。

查詢請求示例

curl -XGET http://localhost:9200/fulltext001/_search?pretty  -H 'Content-Type: application/json' -d '
{
  "from": 0,
  "size": 10,
  "_source": "id",
  "query": {
    "bool": {
      "must": [
        {"match": {"content":"虎嗅"}}
      ]
    }
  },
  "sort": [
    {
      "id": {
        "order": "asc"
      }
    }
  ]
}
'

07

設置teminate_after查詢快速返回

如果不需要精確統計查詢命中記錄條數,可以配teminate_after指定每個shard最多匹配N條記錄後返回,設置查詢超時時間timeout。在查詢結果中可以通過“terminated_early”字段標識是否提前結束查詢請求。

teminate_after查詢語法示例

curl -XGET "http://localhost:9200/twitter/_search" -H 'Content-Type: application/json' -d'
{
  "from": 0,
  "size": 10,
  "timeout": "10s",
  "terminate_after": 1000,
  "query": {
    "bool": {
      "filter": {
        "term": {
          "user": "elastic"
        }
      }
    }
  }
}'

08

避免查詢深度翻頁

Elasticsearch默認只允許查看排序前10000條的結果,當翻頁查看排序靠後的記錄時,響應耗時一般較長。使用search_after方式查詢會更輕量級,如果每次只需要返回10條結果,則每個shard只需要返回search_after之後的10個結果即可,返回的總數據量只是和shard個數以及本次需要的個數有關,和歷史已讀取的個數無關。

search_after查詢語法示例

curl -XGET "http://localhost:9200/twitter/_search" -H 'Content-Type: application/json' -d'
{
  "size": 10,
  "query": {
    "match": {
      "message": "Elasticsearch"
    }
  },
  "sort": [
    {"_score": {"order": "desc"}},
    {"_id": {"order":"asc"}}
  ],
  "search_after": [  
    0.84290016,  //上一次response中某個doc的score
    "1024"  //上一次response中某個doc的id
   ]
}'

09

避免前綴模糊匹配

Elasticsearch默認支持通過*?正則表達式來做模糊匹配,如果在一個數據量較大規模的索引上執行模糊匹配,尤其是前綴模糊匹配,通常耗時會比較長,甚至可能導致內存溢出。儘量避免在高併發查詢請求的生產環境執行這類操作。

某客戶需要對車牌號進行模糊查詢,通過查詢請求"車牌號:*A8848*"查詢時,往往導致整個集羣負載較高。通過對數據預處理,增加冗餘字段"車牌號.keyword",並事先將所有車牌號按照1元、2元、3元...7元分詞後存儲至該字段,字段存儲內容示例:滬,A,8,4,滬A,A8,88,84,48,滬A8...滬A88488。通過查詢"車牌號.keyword:A8848"即可解決原來的性能問題。

10

避免索引稀疏

Elasticsearch6.X之前的版本默認允許在一個index下面創建多個type,Elasticsearch6.X版本只允許創建一個type,Elasticsearch7.X版本只允許type值爲“_doc”。在一個索引下面創建多個字段不一樣的type,或者將幾百個字段不一樣的索引合併到一個索引中,會導致索引稀疏問題。

建議每個索引下只創建一個type,字段不一樣的數據分別獨立創建index,不要合併成一個大索引。每個查詢請求根據需要去讀取相應的索引,避免查詢大索引掃描全部記錄,加快查詢速度。

11

擴容集羣節點個數

升級節點規格

通常服務器節點數越多,服務器硬件配置規格越高,Elasticsearch集羣的處理能力越強。

在不同節點規模下的查詢性能測試

(測試環境:Elasticsearch5.5.3集羣,單節點16核CPU、64G內存、2T SSD盤,10億條人口戶籍登記信息,數據大小1TB, 20索引分片)

集羣節點數副本數
10併發檢索平均響應時間
50併發檢索平均響應時間100併發檢索平均響應時間200併發檢索平均響應時間200併發QPS200併發CPU使用率
200併發CPUIO等待
1
0
77ms
459ms
438ms
1001ms
200
16%
52%
3038ms
103ms
162ms
298ms
669
45%34%
3
2
271ms
356ms
577ms
818ms
244
19%54%
10
0
21ms
36ms
48ms
81ms
2467
40%10%

不同集羣節點規模寫入性能測試

(測試環境:Elasticsearch6.3.2集羣,單節點16核CPU、64G內存、2T SSD盤,10億條人口戶籍登記信息,單條記錄1KB,數據集大小1TB,20個併發寫入線程)

集羣節點數
副本數
寫入TPS
耗時
集羣CPU使用率
10
0
88945
11242s
50%
50
0180638
5535s
20%

在條件允許的情況下,建議可以通過實際的數據和使用場景測試出適合自己的最佳實踐。得益於阿里雲Elasticsearch提供的彈性擴容功能,阿里雲Elasticsearch用戶可以在實際使用時根據情況隨時增加磁盤大小、擴容節點個數、升級節點規格。

< END >

 or 

            

推薦閱讀:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章