前言
大家好,我是路由器沒有路。
今天跟大家聊下自己在工作中總結的關于使用 ElasticSearch 的一些規範,如有不當的地方,歡迎指正。
Elasticsearch 是一個基于 Lucene 的搜尋引擎,支援分布式搜尋、多租戶、實時搜尋和分析等能力,具有高效、穩定、可擴充的優勢,被廣泛應用于企業級搜尋和資料分析場景。
關于 ElasticSearch 的介紹,這裡不再贅述了,有興趣的同學可以看下我前面寫的一篇文章:Elasticsearch 的簡單介紹和如何使用。
基礎配置規劃
分片(shard)容量
- 非日志型(搜尋型、線上業務型)的 shard 容量在 20~40GB(建議在 20G)
- 日志型的 shard 容量在 35~100GB(建議 35G)
- 單個 shard 的文檔個數不能超過 20 億左右(Integer.MAX_VALUE - 128)
注:一個 shard 就是一個 lucene 分片,ES 底層基于 lucene 實作。
索引(index)數量
大索引需要拆分:提高性能,降低風險,将風險分散化。
反例:例如一個 10 多 T 的索引,按 date 查詢、name 查詢
正例:indexname 拆成多個 index_name${date}
正例:indexname 按 hash 拆分 index_name{1,2,3,...100..}
節點、分片、索引
一個節點管理的 shard 數不要超過 200 個
索引 mapping 的設計原則
大原則:不使用預設配置和動态 mapping、資料用途(類型、分詞、存儲、排序)弄清,下面是一個标準 mapping:
json複制代碼{
"aliases": {
"my_index_name": {}
},
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "12",
"number_of_replicas": "1",
"search.slowlog.threshold.query.warn": "5s",
"search.slowlog.threshold.query.info": "1s",
"search.slowlog.threshold.fetch.warn": "1s",
"search.slowlog.threshold.fetch.info": "800ms",
"indexing.slowlog.threshold.index.warn": "12s",
"indexing.slowlog.threshold.index.info": "2s"
}
},
"mappings": {
"_default_": {
"_all": {
"enables": false
}
},
"my_type_name": {
"properties": {
"xxx_id": {
"type": "keyword"
},
"timestamp": {
"type": "long"
},
"xxx_status": {
"type": "integer"
},
"xxx_content": {
"type": "ztext"
}
}
}
}
}
refresh 頻率(refresh_interval)
ES 的定位是準實時搜尋引擎,該值預設是 1s,表示寫入後 1 秒後可被搜尋到,是以這裡的值取決于業務對實時性的要求。
注意這裡并不是越小越好,重新整理頻率高也意味着對 ES 的開銷也大,通常業務類型在 1-5s,日志型在 30s-120s,如果集中導入資料可将其設定為-1,ES 會自動完成資料重新整理(注意完成後更改回來,否則後續會出現搜尋不到資料)。
别名(aliases)
記住:在某些場景下可使用别名,但不要過度依賴别名功能。
正例:
索引名:index_name_v1
别名:index_name
未來重建 index_name_v2 索引,對于業務來說隻需要換别名。
type 個數
1 個就夠了,從 ES6 開始隻支援一個 type,這個 type 比較雞肋,後面的版本可能會去掉。
如果一定用:針對已經使用多個 type 的場景,一定要保證不同 type 下字段盡量保持一緻,否則會加大資料稀疏性,存儲與查詢性能受影響
慢日志(slowlog)
一定要配置,預設不記錄慢查詢,kcc 提供了 grafana、kibana 查詢功能。
副本(number_of_replicas)
1 個就夠用,副本多寫入壓力不可忽視。極端情況下:譬如批量導入資料,可以将其調整為 0。
字段設計
- text 和 keyword 的用途必須厘清:分詞和關鍵詞(确定字段是否需要分詞)
- 确定字段是否需要獨立存儲
- 字段類型不支援修改,必須謹慎
- 對不需要進行聚合/排序的字段禁用 doc_values
- 不要在 text 做模糊搜尋
text 類型:适用于分詞用于搜尋,适用于 email 、内容、描述等需要分詞的全文檢索,不适用聚合。
keyword 類型:無需分詞,整段完整精确比對,适用于:email 、位址、狀态碼、分類 tags。
設定合理的 routing key(預設是 id)
id 不均衡:叢集容量和通路不均衡,對于分布式存儲是緻命的。
關閉 _all
ES6.0 已經去掉,對容量(索引過大)和性能(性能下降)都有影響。
避免大寬表:
ES 預設最大 1000,但建議不要超過 100
text 類型的字段不要使用聚合查詢
text 類型 fileddata 會加大對記憶體的占用,如果有需求使用,建議使用 keyword
聚合查詢避免使用過多嵌套,
聚合查詢的中間結果和最終結果都會在記憶體中進行,嵌套過多,會導緻記憶體耗盡。
以下是聚合就嵌套了 3 層,結果都會儲存在記憶體中,
如果唯一值較多,就會導緻記憶體耗盡:
json複制代碼{
"aggs": {
"country": {
"terms": {
"filed": "country",
"size": 10
},
"aggs": {
"city": {
"terms": {
"filed": "city",
"size": 20
},
"aggs": {
"salary": {
"terms": {
"filed": "salary",
"size": 20
}
}
}
}
}
}
}
}
謹慎操作
- 原則:不要忽略設計,快就是慢,壞的索引設計後患無窮.
- 拒絕大聚合 :ES 計算都在 JVM 記憶體中完成。
- 拒絕模糊查詢:es 一大殺手
- 即 wildcard 搜尋
- json複制代碼
- { "query": { "wildcard": { "title.keyword": "*張三*" } } }
- 拒絕深度分頁 ES 擷取資料時,每次預設最多擷取 10000 條,擷取更多需要分頁,但存在深度分頁問題,一定不要使用 from/Size 方式,建議使用 scroll 或者 searchAfter 方式。
- scroll 會把上一次查詢結果緩存一定時間(通過配置 scroll=1m 實作),是以在使用 scroll 時一定要保證 search 結果集不要太大。
- 基數查詢 盡量不要用基數查詢去查詢去重後的資料量大小(kibana 中界面上顯示是 Unique Count,Distinct Count 等)
- 即少用以下查詢:
- json複制代碼
- "aggregations": { "cardinality": { "field": "userId" } }
- 禁止查詢 indexName-*
- 避免使用 script、update_by_query、delete_by_query,對線上性能影響較大。
需注意的問題
- 一個索引的 shard 數一旦确定不能改變
- ES 不支援事務 ACID 特性。
- reindex: reindex 可以實作索引的 shard 變更,但代價非常大:速度慢、對性能有影響,是以好的設計和規劃更重要
總結
以上是自己在工作中總結的關于 ElasticSearch 的使用規範,如對你有幫助,可以給個贊。
另外,Elasticsearch 的使用需要結合實際業務場景,通過優化和管理來提高其性能和穩定性,我們需要根據特定的業務場景和使用需求來選擇合适的方案。
原文連結:https://juejin.cn/post/7244819106343518268