如何合理規(guī)劃Elasticsearch的索引
一、背景
隨著ES在業(yè)務(wù)場景中的使用逐漸增多,平臺(tái)對(duì)ES集群的穩(wěn)定性、管理、運(yùn)維的壓力逐漸增大,通過日常的運(yùn)維情況來看,發(fā)現(xiàn)用戶對(duì)ES的了解熟悉程度參差不齊,經(jīng)常性的遇到索引創(chuàng)建不規(guī)范,或者參考別人索引的創(chuàng)建腳本進(jìn)行創(chuàng)建索引,對(duì)索引沒有一個(gè)比較清晰的認(rèn)知,對(duì)索引結(jié)構(gòu)的規(guī)劃也寥寥無幾,為此,平臺(tái)使用了一些列手段來幫助用戶提前合理規(guī)劃模板,比如索引、模板的創(chuàng)建接入飛書審批流,平臺(tái)側(cè)會(huì)逐一結(jié)合業(yè)務(wù)場景和ES集群情況詳細(xì)溝通確定索引或者模板結(jié)構(gòu);又比如ES內(nèi)核增加業(yè)務(wù)不停服的動(dòng)態(tài)擴(kuò)分片能力,旨在進(jìn)行不合理索引的治理提升ES集群穩(wěn)定性(索引一旦創(chuàng)建分片是不能修改的),我們內(nèi)部改動(dòng)ES源碼實(shí)現(xiàn)了不停服動(dòng)態(tài)擴(kuò)分片。
因此有必要從ES的索引講起,讓大家對(duì)ES的索引從概念、原理到使用有一個(gè)清晰的認(rèn)知,希望日常業(yè)務(wù)場景中用到ES的同學(xué)能夠抽時(shí)間讀一下。當(dāng)然文章避免不了存在主觀的分析,大家可以在文章底部進(jìn)行評(píng)論或者私聊我們,一起探討。好了廢話不多說了,現(xiàn)在開始介紹。
二、什么是index(索引)
下面會(huì)針對(duì)索引的組成和基本結(jié)構(gòu)結(jié)合官方文檔逐一介紹。
基本概念
index(索引)是索引是具有相似特征的文檔(Document)集合,類似于關(guān)系型數(shù)據(jù)庫中的表。每個(gè)索引都具有自己唯一的名稱與_id。并且可以進(jìn)行不同的參數(shù)配置與mapping映射。以適應(yīng)不同的業(yè)務(wù)場景。索引中的最小單位是文檔。每一條文檔(doc)都是一個(gè)json格式的數(shù)據(jù)對(duì)象。包含了實(shí)際的具體數(shù)據(jù)以及該數(shù)據(jù)所對(duì)應(yīng)的元數(shù)據(jù)。文檔可以是結(jié)構(gòu)化,半結(jié)構(gòu)化或非結(jié)構(gòu)化的數(shù)據(jù)。索引在elasticsearch中被用于存儲(chǔ),檢索與分析數(shù)據(jù)。通過對(duì)索引進(jìn)行搜索與聚合操作可以快速地找到相關(guān)的文檔。
官方描述:The index is the fundamental unit of storage in Elasticsearch, a logical namespace for storing data that share similar characteristics. After you have Elasticsearch deployed, you’ll get started by creating an index to store your data.
翻譯:索引是Elasticsearch中存儲(chǔ)數(shù)據(jù)的基本單位,是一個(gè)邏輯命名空間,用于存儲(chǔ)具有相似特性的數(shù)據(jù)。在部署Elasticsearch后,您將通過創(chuàng)建索引來存儲(chǔ)數(shù)據(jù)。
An index is a collection of documents uniquely identified by a name or an alias. This unique name is important because it’s used to target the index in search queries and other operations.
翻譯:索引是一種文檔集合,通過名稱或別名唯一標(biāo)識(shí)。這個(gè)唯一名稱非常重要,因?yàn)樗糜谠谒阉鞑樵兒推渌僮髦卸ㄎ凰饕?/p>
三、索引結(jié)構(gòu)詳解
索引結(jié)構(gòu)詳解
圖片
創(chuàng)建索引結(jié)構(gòu)
PUT /index_demo
{
"aliases" : {
"index_demo_alias" : { }
},
"mappings" : {
"properties" : {
"id" : {
"type" : "long"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"status" : {
"type" : "keyword"
},
"createDate" : {
"type" : "long"
}
}
},
"settings" : {
"index" : {
"refresh_interval" : "5s",
"number_of_shards" : "3",
"number_of_replicas" : "1"
}
}
}
ignore_above屬性說明:
- ignore_above的默認(rèn)值通常為256個(gè)字符,這意味著任何超過256個(gè)字符的字符串將不會(huì)被索引或存儲(chǔ)。
- 該參數(shù)僅適用于keyword類型的字段,因?yàn)檫@些字段主要用于過濾、排序和聚合操作,不需要進(jìn)行全文搜索。
- ignore_above的值以字符為單位計(jì)算,包括英文字符和漢字。例如,一個(gè)漢字和一個(gè)英文字符都算作一個(gè)字符。
- 性能優(yōu)化:通過限制字段長度,可以減少索引大小和查詢時(shí)間,從而提高性能。
- 避免資源浪費(fèi):對(duì)于包含大量數(shù)據(jù)的字段,如日志文件中的長字符串,可以通過ignore_above避免不必要的存儲(chǔ)和索引。
官方描述:Strings longer than the ignore_above setting will not be indexed or stored. For arrays of strings, ignore_above will be applied for each array element separately and string elements longer than ignore_above will not be indexed or stored.
別名
別名將其生命置于群集狀態(tài)內(nèi),由主節(jié)點(diǎn)(master node) 管理; 這意味著如果你有一個(gè)名為 xiaoming 的別名指向一個(gè)名為 potato 的索引,那么開銷就是群集狀態(tài)映射中的一個(gè)額外鍵,它將名稱 xiaoming 映射到具體的索引字符串。這意味著與其他指數(shù)相比,別名的重量要輕得多; 可以維護(hù)數(shù)千個(gè)而不會(huì)對(duì)集群產(chǎn)生負(fù)面影響。
官方原話:An alias points to one or more indices or data streams. Most Elasticsearch APIs accept an alias in place of a data stream or index name.
Aliases enable you to:
- Query multiple indices/data streams together with a single name
- Change which indices/data streams your application uses in real time
- Reindex data without downtime
翻譯:別名(Alias)可以指向一個(gè)或多個(gè)索引或數(shù)據(jù)流。大多數(shù)Elasticsearch API接受別名代替數(shù)據(jù)流或索引名稱。別名的功能包括:
- 使用單一名稱查詢多個(gè)索引/數(shù)據(jù)流;
- 實(shí)時(shí)更改應(yīng)用程序使用的索引/數(shù)據(jù)流;
- 在不中斷服務(wù)的情況下進(jìn)行擴(kuò)分片。
可以看到索引有上面三個(gè)作用,平臺(tái)建議為每個(gè)索引添加別名(動(dòng)態(tài)擴(kuò)分片依賴別名)。添加別名可以在索引創(chuàng)建時(shí)和創(chuàng)建后再添加,即索引可以隨時(shí)添加,但是平臺(tái)還是建議你在創(chuàng)建索引時(shí)候指定別名,避免動(dòng)態(tài)擴(kuò)分片時(shí)候再去修改代碼重新部署應(yīng)用。
添加別名的幾種方式
1. 創(chuàng)建索引時(shí)指定別名
PUT /test_index
{
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : 1
},
"aliases":{"test_alias":{}},
"mappings" : {
"properties" : {
"field1" : {
"type" : "text"
},
"createdAt": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
2. 已存在的索引添加別名
POST /_aliases
{
"actions": [
{
"add": {
"index": "test_index", # 索引名
"alias": "test_alias" # 別名
}
}
]
}
3. 別名更換
別名更換可以零停機(jī)進(jìn)行動(dòng)態(tài)擴(kuò)分片。
POST /_aliases
{
"actions": [
{
"add": {
"index": "existing_index",
"alias": "test_alias" # 別名
},
{
"remove": {
"index": "old_index",
"alias": "old_test_alias" # 別名
}
}
}
]
}
映射
建立索引時(shí)需要定義文檔的數(shù)據(jù)結(jié)構(gòu),這種結(jié)構(gòu)叫作映射。在映射中,文檔的字段類型一旦設(shè)定后就不能更改。因?yàn)樽侄晤愋驮诙x后,elasticsearch已經(jīng)針對(duì)定義的類型建立了特定的索引結(jié)構(gòu),這種結(jié)構(gòu)不能更改。借助映射可以給文檔新增字段。另外,elasticsearch還提供了自動(dòng)映射功能,即在添加數(shù)據(jù)時(shí),如果該字段沒有定義類型,elasticsearch會(huì)根據(jù)用戶提供的該字段的真實(shí)數(shù)據(jù)來猜測可能的類型,從而自動(dòng)進(jìn)行字段類型的定義。
字段類型
字段類型(Field Type)是定義數(shù)據(jù)格式和索引方式的重要概念,它決定了字段在索引中的存儲(chǔ)、搜索和聚合行為。下面針對(duì)日常用到最多的三個(gè)字段類型進(jìn)行解釋,text、keyword、Numeric(Integer、Long)。
Text
text字段類型是Elasticsearch中用于全文搜索的核心字段類型。它通過分析器將文本拆分為單個(gè)詞,并存儲(chǔ)為倒排索引,適用于非結(jié)構(gòu)化文本的搜索和分析。然而,由于其經(jīng)過分析器處理,不適用于排序和聚合操作。
1. 特點(diǎn)
- 全文搜索:text字段類型主要用于存儲(chǔ)和索引可讀的文本內(nèi)容,例如郵件正文、產(chǎn)品描述、新聞文章等。這些字段會(huì)被分析器(analyzer)處理,將字符串拆分為單個(gè)詞(term),以便進(jìn)行全文搜索。
- 分詞處理:text字段支持分詞器(tokenizer),可以根據(jù)語言和需求選擇不同的分詞策略(如標(biāo)準(zhǔn)分詞器、正則表達(dá)式分詞器等)。分詞后的結(jié)果會(huì)存儲(chǔ)為倒排索引,便于快速檢索。
- 不適用于排序和聚合:由于text字段經(jīng)過分析器處理,其原始字符串無法直接用于排序或聚合操作。如果需要排序或聚合,通常需要結(jié)合keyword字段類型。
- 支持多字段映射:可以通過多字段(multi-field)映射同時(shí)使用text和keyword類型,以滿足全文搜索和精確匹配的需求。
2. 使用場景
- 全文搜索:適用于需要對(duì)文本內(nèi)容進(jìn)行模糊搜索的場景,例如搜索引擎、新聞網(wǎng)站、商品搜索等。
- 文本分析:可以結(jié)合分析器(如TF-IDF、BM25等)進(jìn)行文本相似性搜索或評(píng)分計(jì)算。
- 日志分析:用于分析和搜索日志文件中的文本內(nèi)容,提取關(guān)鍵信息。
- 內(nèi)容管理:在內(nèi)容管理系統(tǒng)中,用于存儲(chǔ)和搜索文檔、文章等內(nèi)容。
3. 官方建議
Use a field as both text and keyword
Sometimes it is useful to have both a full text (text) and a keyword (keyword) version of the same field: one for full text search and the other for aggregations and sorting. This can be achieved with multi-fields.
通過多字段映射同時(shí)使用text和keyword類型,可以實(shí)現(xiàn)全文搜索和精確匹配的雙重需求。
4. 平臺(tái)建議
- 明確業(yè)務(wù)使用場景,如果不需要進(jìn)行模糊搜索的話,設(shè)置為keyword類型,來避免分詞帶來的存儲(chǔ)開銷,增加系統(tǒng)壓力。
Keyword
keyword字段類型是一種用于存儲(chǔ)和索引結(jié)構(gòu)化數(shù)據(jù)的字段類型。
1. 特點(diǎn)
- 不進(jìn)行分詞:keyword字段類型不會(huì)對(duì)字段值進(jìn)行分詞處理,而是將其作為整體存儲(chǔ)。這意味著字段值會(huì)被原樣存儲(chǔ)到倒排索引中,不會(huì)被拆分成單獨(dú)的單詞或短語。
- 精確匹配:由于字段值不進(jìn)行分詞,keyword字段類型非常適合用于精確匹配查詢,例如查找特定的電子郵件地址、身份證號(hào)或狀態(tài)碼等。
- tips:在term查詢中可以結(jié)合case_insensitive屬性,忽略大小寫對(duì)值進(jìn)行搜索,但不支持terms查詢。
- 支持排序和聚合:keyword字段類型可以用于排序和聚合操作,例如按狀態(tài)碼統(tǒng)計(jì)數(shù)量或按用戶ID進(jìn)行分組。
- 存儲(chǔ)效率高:由于不需要分詞,keyword字段類型的存儲(chǔ)開銷較低,適合存儲(chǔ)大量具有唯一性或固定值的字段。
2. 使用場景
- 精確查詢:適用于需要精確匹配的場景,例如查找特定的電子郵件地址、身份證號(hào)、狀態(tài)碼等。
- 排序和聚合:當(dāng)需要對(duì)數(shù)據(jù)進(jìn)行排序或聚合時(shí),keyword字段類型是理想選擇。例如,按用戶ID排序或按狀態(tài)統(tǒng)計(jì)數(shù)量。
- 標(biāo)簽和分類:用于存儲(chǔ)標(biāo)簽、分類等結(jié)構(gòu)化數(shù)據(jù),例如用戶畫像標(biāo)簽(學(xué)生、IT、教師等)。
- 唯一性字符串:適用于存儲(chǔ)具有唯一性的字符串,如SpuId、貨號(hào)、得物訂單號(hào)等。
Numeric
數(shù)值類型,包含long、interger、short、byte、double、float等數(shù)字類型。
1. 特點(diǎn)
- 整數(shù)類型:適用于范圍查詢、排序和聚合操作。由于整數(shù)類型占用空間較小,推薦優(yōu)先使用范圍較小的類型(如 integer 或 long)以提高索引和搜索效率。
- 浮點(diǎn)類型:適用于需要高精度的計(jì)算場景。如果數(shù)據(jù)范圍較大或精度要求不高,可以使用 scaled_float 類型并設(shè)置合適的 scale 值。
- 選擇合適的類型:在滿足需求的前提下,盡量選擇范圍較小的類型以節(jié)約存儲(chǔ)空間和提升性能。
tips
如果確定業(yè)務(wù)使用場景,建議keyword代替數(shù)值類型字段,如果不確定則采用多字段,keyword在term查詢中性能更佳。
圖片
針對(duì)字段類型選擇的幾條建議
- 針對(duì)Text和數(shù)值類型場景的字段,盡量改成keyword字段類型,來提升查詢速度。
- 在不確定業(yè)務(wù)查詢有哪些需求的情況下,設(shè)置多字段類型keyword。
- 枚舉字段沒有特殊業(yè)務(wù)場景下,統(tǒng)一使用keyword字段類型。
- 業(yè)務(wù)不需要范圍查詢的話,使用keyword字段類型(支持聚合和排序的)。
- 對(duì)keyword字段類型進(jìn)行模糊查詢會(huì)性能較差,使用多字段類型wildcard來模糊查詢性能更高。
- 盡量不要使用聚合查詢,text的fielddata會(huì)加大對(duì)內(nèi)存的占用,如有需求使用,建議使用keyword。
- 需要中文分詞的話,不要使用默認(rèn)分詞器,推薦使用ik_smart,ik_max_word會(huì)生成更多的分詞,其中含有重復(fù)的內(nèi)容,需謹(jǐn)慎使用。
- 時(shí)間字段不要使用keyword,除非點(diǎn)查,推薦使用date/long類型,支持范圍查詢,建議精確到分鐘,會(huì)提高查詢效率。
- keyword字段類型不適用于模糊wildcard查詢,建議使用wildcard字段類型。
圖片
- 日期的查詢條件為now時(shí),并不能有效利用緩存,盡量換成絕對(duì)時(shí)間值。
- ES默認(rèn)字段個(gè)數(shù)最大1000,但建議不要超過100,對(duì)于不需要建立索引的字段,不寫入ES。
- 將不需要建立索引的字段index數(shù)據(jù)設(shè)置為false,對(duì)字段不分詞,不索引可以減少很多運(yùn)算操作。
- 不建議或者禁止每次寫入后立馬進(jìn)行顯示的refresh,refresh會(huì)帶來較高的磁盤IO,和CPU消耗,甚至有可能導(dǎo)致ES宕機(jī)。
- 持續(xù)補(bǔ)充......
索引結(jié)構(gòu)與關(guān)系性數(shù)據(jù)庫對(duì)比
圖片
四、索引(Shard)結(jié)構(gòu)-分片與副本
什么是Shard
基本概念
分片是管理文檔的一個(gè)數(shù)據(jù)單元,分片是Elasticsearch中邏輯概念。ES內(nèi)部把索引中文檔進(jìn)行按照一定路由規(guī)則(文檔_id的hash值與分片數(shù)取余)進(jìn)行路由到不同的存儲(chǔ)數(shù)據(jù)單元,存儲(chǔ)數(shù)據(jù)單元就是分片。你可以理解為MySQL的分表。
ElS的邏輯分片就是一個(gè)Lucene索引,一個(gè)ES索引是分哦的集合,當(dāng)ES在索引中搜索的時(shí)候,他發(fā)送查詢到每一個(gè)屬于索引的分片(Lucene索引)進(jìn)行檢索,最后合并每個(gè)分片的結(jié)果得到一個(gè)全局的結(jié)果集。
分片劃分
分片分為primary shard(主分片)和replicate shard(副本分片)。
- 主分片:索引的基本數(shù)據(jù)存儲(chǔ)單元,每個(gè)索引被水平拆分為多個(gè)主分片,每個(gè)分片都是互相獨(dú)立的。包含一部分索引的數(shù)據(jù)與索引的結(jié)構(gòu)(segement)。每個(gè)分片都可以在集群中不同的節(jié)點(diǎn)上進(jìn)行移動(dòng)與復(fù)制。以提高數(shù)據(jù)的可用性與容錯(cuò)性。
- 副本分片:主分片的完整拷貝,用于冗余存儲(chǔ)和容災(zāi),副本分片和主分片在ES節(jié)點(diǎn)數(shù)足夠的情況下不會(huì)同時(shí)存在一個(gè)ES節(jié)點(diǎn)。
注意:單分片的記錄條數(shù)不要超過上限2,147,483,519。
- 主副分片分布示意圖
圖片
分片的功能
1. 主分片
- 數(shù)據(jù)存儲(chǔ)與寫入:所有文檔通過路由算法(如 hash(_id) % num_primary_shards(主分片數(shù)))分配到主分片,主分片負(fù)責(zé)處理索引、更新、刪除等寫操作。
- 擴(kuò)展性:通過增加節(jié)點(diǎn)和分片分布,實(shí)現(xiàn)數(shù)據(jù)的水平擴(kuò)展。
- 不可變性:主分片數(shù)量在索引創(chuàng)建時(shí)通過 number_of_shards 參數(shù)設(shè)定,創(chuàng)建后無法修改(需重建索引)。
2. 副本分片
- 高可用性:當(dāng)主分片所在節(jié)點(diǎn)宕機(jī)時(shí),副本分片自動(dòng)升級(jí)為主分片(和對(duì)應(yīng)的主分片不在一個(gè)節(jié)點(diǎn)),避免數(shù)據(jù)丟失和服務(wù)中斷。
- 讀取負(fù)載均衡:副本分片可并行處理查詢請(qǐng)求,提升讀吞吐量。
- 動(dòng)態(tài)調(diào)整:副本分片數(shù)量通過 number_of_replicas 參數(shù)動(dòng)態(tài)配置,支持按需擴(kuò)展或縮減。
分片數(shù)規(guī)劃
分片的基本概念和功能咱們?cè)蹅円呀?jīng)了解,在日常ES運(yùn)維過程中發(fā)現(xiàn)不少同學(xué)對(duì)分片和數(shù)量的設(shè)置沒有什么概念,照搬其他同學(xué)的比較多,這是嚴(yán)重錯(cuò)誤的。咱們?cè)趯?shí)際的業(yè)務(wù)場景中也要做好分片(主副)數(shù)量的規(guī)劃,來避免慢查、數(shù)據(jù)傾斜、磁盤容量浪費(fèi)等問題。
當(dāng)索引分片數(shù)量過多時(shí),可能會(huì)對(duì)ES性能產(chǎn)生不利影響。因?yàn)槊總€(gè)分片都需要一定量的內(nèi)存來存儲(chǔ)索引數(shù)據(jù)和緩存,從而導(dǎo)致內(nèi)存消耗增加。另外當(dāng)查詢或?qū)懭霐?shù)據(jù)涉及多個(gè)分片時(shí),ES需要在節(jié)點(diǎn)之間進(jìn)行傳輸和協(xié)調(diào)數(shù)據(jù),從而增加網(wǎng)絡(luò)開銷,這也會(huì)導(dǎo)致查詢和寫入性能的降低。可見分片數(shù)量的選擇需要慎重考慮。
索引在不同場景中,其分片分設(shè)置是不一樣的,接下來咱們會(huì)在下面四個(gè)場景中來進(jìn)行闡述。
讀場景
索引單分片20g~40g,盡量減少分片數(shù),可以降低熱點(diǎn),因?yàn)楫?dāng)分片數(shù)過多時(shí),就容易出現(xiàn)長尾子請(qǐng)求,即有可能部分子請(qǐng)求因ES集群節(jié)點(diǎn)異常、Old GC、網(wǎng)絡(luò)抖動(dòng)等延遲響應(yīng),導(dǎo)致整個(gè)請(qǐng)求響應(yīng)緩慢。另一方面,拆分過多的子請(qǐng)求無法提升數(shù)據(jù)節(jié)點(diǎn)請(qǐng)求吞吐,不能充分利用 CPU。在盡量減少主分片數(shù)的情況下,同時(shí)也可以適當(dāng)增加副本數(shù),從而提升查詢吞吐。
寫場景
索引單分片10g~20g,小分片更有利于數(shù)據(jù)寫入。小分片維護(hù)的segment數(shù)量遠(yuǎn)低于大分片,在數(shù)據(jù)刷新落盤與段合并上更有優(yōu)勢(shì)。由于單分片數(shù)據(jù)量更少,在寫入時(shí)數(shù)據(jù)可以更快地緩存至內(nèi)存中并通過refresh參數(shù)更快的持久化至磁盤中。
日志存儲(chǔ)場景
- 需要考慮每日寫入集群的數(shù)據(jù)總量大小。通過過數(shù)據(jù)量與數(shù)據(jù)節(jié)點(diǎn)數(shù)評(píng)估索引分片數(shù)量。
- 在日志存儲(chǔ)后是否需要兼顧查詢與聚合性能。合理大小的分片數(shù)據(jù)量能夠提高查詢效率。
- 根據(jù)日志持久化策略,采用按月/周/天的策略生成索引。并使用ILM(索引生命周期管理策略)動(dòng)態(tài)對(duì)日志索引進(jìn)行完整生命周期的管理。
- 建議副本數(shù)設(shè)置為0來減少磁盤容量成本。
小數(shù)據(jù)量索引業(yè)務(wù)場景
對(duì)于數(shù)據(jù)量比較小的索引,增加索引分片數(shù)并不一定會(huì)帶來性能提升,反而可能會(huì)帶來一些負(fù)面影響。
首先,增加索引分片數(shù)會(huì)增加集群的管理開銷,包括維護(hù)分片的狀態(tài)、備份和恢復(fù)分片等。如果索引數(shù)據(jù)量比較小,這種開銷可能會(huì)超過性能提升帶來的收益。
其次,增加索引分片數(shù)可能會(huì)導(dǎo)致數(shù)據(jù)分布不均衡,從而影響查詢性能。具體來說,如果某些分片中的數(shù)據(jù)量過小,可能會(huì)導(dǎo)致這些分片的查詢性能比其他分片差。此外,如果查詢涉及到多個(gè)分片,數(shù)據(jù)的合并操作也會(huì)增加查詢時(shí)間。
因此,對(duì)于數(shù)據(jù)量比較小的索引,在查詢場景下,通常建議將分片數(shù)設(shè)置為1或2,以避免不必要的開銷和性能問題。如果需要提高查詢性能,可以考慮配置索引副本,優(yōu)化查詢語句或使用緩存。
通用場景
- 根據(jù)實(shí)際業(yè)務(wù)場景提前規(guī)劃預(yù)算索引數(shù)據(jù)量,做好分片數(shù)量規(guī)劃(索引一旦創(chuàng)建無法修改分片數(shù))。
- 分片數(shù)量:推薦公式:主分片數(shù) ≈ 總數(shù)據(jù)量 / 單分片容量上限(官方建議單分片10-50GB,單個(gè)分片文檔數(shù)在1億條以內(nèi),日志場景可放寬至50-100GB)。
注意:分片數(shù)量平臺(tái)強(qiáng)烈建議或者要求設(shè)置為ES data節(jié)點(diǎn)角色的整數(shù)倍。
- 副本數(shù)量:增加副本數(shù)可提升讀性能,但會(huì)降低寫入速度(需同步更多副本),因此在讀場景可以酌情考慮。
- 如果索引是時(shí)序類,或者數(shù)據(jù)過大,單分片幾百G,可以結(jié)合生命周期和索引模板進(jìn)行索引滾動(dòng)管理。
- 平臺(tái)不建議使用自動(dòng)移routing值進(jìn)行分片,默認(rèn)使用文檔_id就好。
原因:使用自定義routing值進(jìn)行路由分片的話很容易產(chǎn)生數(shù)據(jù)傾斜,另外ES內(nèi)部會(huì)多一些計(jì)算邏輯來如何進(jìn)行分片路由,在寫入較高的場景下也會(huì)有一定的性能損耗。
- 控制分片數(shù)量,分片數(shù)不是越多越好,過多分分片,也會(huì)造成ES集群元數(shù)據(jù)管理的壓力,降低系統(tǒng)的性能損耗。
- 設(shè)置total_shards_per_node,將索引壓力分?jǐn)傊炼鄠€(gè)節(jié)點(diǎn)。
- index.routing.allocation.total_shards_per_node參數(shù)可以限制每個(gè)節(jié)點(diǎn)上的shard數(shù)量,從而將索引的壓力分?jǐn)偟蕉鄠€(gè)節(jié)點(diǎn),這樣可以提高集群性能和可用性,避免某個(gè)節(jié)點(diǎn)過載導(dǎo)致整個(gè)集群出現(xiàn)問題。
- index.routing.allocation.total_shards_per_node是一個(gè)索引級(jí)別設(shè)置(創(chuàng)建索引和對(duì)已有索引進(jìn)行設(shè)置),語法如下:
PUT <index_name>/_settings
{
"index.routing.allocation.total_shards_per_node":<number_of_shards>
}
<index_name>為索引名字,<number_of_shards>表示每個(gè)節(jié)點(diǎn)上該索引的分片數(shù)量。
持續(xù)調(diào)整索分片
對(duì)于集群分片的調(diào)整,通常不是一蹴而就的。隨著業(yè)務(wù)的發(fā)展,不斷新增的子業(yè)務(wù) 或 原有子業(yè)務(wù)規(guī)模發(fā)生突變,都需要持續(xù)調(diào)整分片數(shù)量。
索引與資源消耗的關(guān)系
分片數(shù)量與內(nèi)存消耗
每個(gè)分片都是獨(dú)立的Lucene索引,需要維護(hù)倒排索引、緩存等內(nèi)存結(jié)構(gòu)。分片數(shù)量過多會(huì)導(dǎo)致以下問題:
- 內(nèi)存占用激增:每個(gè)分片默認(rèn)占用約10-30MB內(nèi)存(含元數(shù)據(jù)),數(shù)千分片可能消耗數(shù)十GB內(nèi)存。
- 文件句柄耗盡:集群總分片數(shù)過多會(huì)占用大量文件描述符,可能觸發(fā)"too many open files"錯(cuò)誤。
- CPU熱點(diǎn)問題:分片分配不均會(huì)導(dǎo)致部分節(jié)點(diǎn)負(fù)載過高。
Segment碎片化
分片由多個(gè)segment組成,segment數(shù)量過多會(huì):
- 增加IO壓力:查詢需遍歷多個(gè)segment文件。
- 占用堆內(nèi)存:每個(gè)segment需加載部分元數(shù)據(jù)到內(nèi)存,百萬級(jí)segment可能消耗數(shù)GB內(nèi)存。
- 影響GC效率:頻繁的segment合并會(huì)觸發(fā)Full GC。
五、總結(jié)
創(chuàng)建一個(gè)索引需要結(jié)合業(yè)務(wù)使用場景考量字段類型選擇和是否需要索引分詞,按照數(shù)據(jù)規(guī)模和業(yè)務(wù)增長速度來確定分片和副本的數(shù)量的大小。索引的結(jié)構(gòu)直接影響集群的穩(wěn)定性,因此我們?cè)趧?chuàng)建索引的時(shí)候要養(yǎng)成習(xí)慣,作為技術(shù)方案的一環(huán)去仔細(xì)打磨這樣才能保證線上的穩(wěn)定性。
大家工作中遇到的一些穩(wěn)定性問題,和使用上的一些問題都可以找我們一起探討,尋找最優(yōu)解。