本文為部落格園作者所寫: 一寸HUI,個人部落格地址:https://www.cnblogs.com/zsql/
最近在做es相關的工作,所以記錄下自己的一些想法,可能很多方面不會很全面,但是基本都是經過驗證的。本文主要是圍繞著思考,從多個方面進行考慮,怎麼設計索引比較好,直接進入主題吧,本文的es版本為elasticsearch7.8.1。
一、索引設計的重要性
首先索引建立後,索引的分片只能通過_split和_shrink介面對其進行成倍的增加和縮減,主要是因為es的資料是通過_routing分配到各個分片上面的,所以本質上是不推薦去改變索引的分片數量的,因為這樣都會對資料進行重新的移動。還有就是索引只能新增欄位,不能對欄位進行修改和刪除,缺乏靈活性,所以每次都只能通過_reindex重建索引了。還有就是一個分片的大小以及所以分片數量的多少嚴重影響到了索引的查詢和寫入效能。所以可想而知,設計一個好的索引能夠減少後期的運維管理和提高不少效能。所以前期對索引的設計是相當的重要的。
- 好的索引設計在整個叢集規劃中佔據舉足輕重的作用,索引的設計直接影響叢集設計的好壞和複雜度。
- 好的索引設計應該是充分結合業務場景的時間維度和空間維度,結合業務場景充分考量增、刪、改、查等全維度設計的。
- 好的索引設計是完全基於“設計先行,編碼在後”的原則,前期會花很長時間,為的是後期工作更加順暢,避免不必要的返工
二、如何設計索引
在設計索引之前我們要明白索引有些什麼內容,明白索引的構成,比如索引的基本配置setting,對映mapping,還有重要的分片,副本,模板,索引的生命週期等。知道這些之後就可以有針對性的設計了。首先要結合公司的業務場景,資料量的大小,每天增量如何,資料的特點,會不會對歷史資料進行重新更新。資料存多久,是永久還是有一定的週期。資料需要準實時呢還是不需要準實時呢。所以清楚索引的構成和知道業務場景,才能夠結合起來做更好的設計。
2.1、考慮索引的公共基本配置
由於elasticsearch7.x不允許把索引級別的設定配置在elasticsearch.yml中,所以需要對每個索引進行單獨的配置,這樣的話就比較麻煩,所以可以把這些公共的配置配置在索引模板中,這樣就可以在新建索引的時候可以自動的設定到索引中,關於索引模板的操作可以看考:聊聊elasticsearch7.8的模板和動態對映
接下來看看一些常用索引級別的配置
"number_of_replicas": 1, #推薦副本數為1
"max_result_window": 100000,
"refresh_interval": "30s", #這裡對實時性要求不高,可以增加該值提高寫入效能
"index.search.slowlog.threshold.query.warn": 10s,
"index.search.slowlog.threshold.query.info": 5s,
"index.search.slowlog.threshold.query.debug": 2s,
"index.search.slowlog.threshold.query.trace": 500ms,
"index.search.slowlog.threshold.fetch.warn": 1s,
"index.search.slowlog.threshold.fetch.info": 800ms,
"index.search.slowlog.threshold.fetch.debug": 500ms,
"index.search.slowlog.threshold.fetch.trace": 200ms,
"index.indexing.slowlog.threshold.index.warn": 10s,
"index.indexing.slowlog.threshold.index.info": 5s,
"index.indexing.slowlog.threshold.index.debug": 2s,
"index.indexing.slowlog.threshold.index.trace": 500ms
"dynamic": false #是否關閉動態欄位對映,預設為true,這裡選擇個人選擇禁用
當然索引的配置還有很多其他的,可以根據實際情況進行調整,這樣就可以把需要配置公共索引配置設計成索引模板:
PUT _index_template/template_index
{
"index_patterns": [
"index-*"
],
"template": {
"settings": {
"number_of_replicas": 1,
"max_result_window": 100000,
"refresh_interval": "30s",
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.query.debug": "2s",
"index.search.slowlog.threshold.query.trace": "500ms",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.search.slowlog.threshold.fetch.info": "800ms",
"index.search.slowlog.threshold.fetch.debug": "500ms",
"index.search.slowlog.threshold.fetch.trace": "200ms",
"index.indexing.slowlog.threshold.index.warn": "10s",
"index.indexing.slowlog.threshold.index.info": "5s",
"index.indexing.slowlog.threshold.index.debug": "2s",
"index.indexing.slowlog.threshold.index.trace": "500ms"
},
"mappings": {
"dynamic": false
}
},
"priority": 10
}
這樣新建index-開頭的索引的時候都會預設配置好如上的配置,這樣就是考慮到基本設定公共化
2.2、索引命名規範
這部分主要說下索引命名規範,包括別名,通過別名可以使得索引的操作變得更加靈活,一個索引可以有多個別名,當然一個別名可以配置多個索引,這樣的話就極大的增加了索引的的靈活性。在索引的命名上規定特殊欄位開頭,同樣對其好進行許可權控制,關於許可權控制可以參考:elasticsearch7.8許可權控制和規劃
必須嚴格按照如下命名格式:(否則將無法使用,因為這裡設定了相關許可權);
- 索引命名規範:index-{行業}-{業務}-{版本}
- 別名命名規範:index-{行業}-{業務}
如果是索引拆分後(有多個索引),需要一個全域性的讀的別名對所有拆分後的所有進行命名,和一個最新索引寫的別名(只對可更新的索引),如果這裡沒有描述清楚,請見2.5大索引的設計,兩個別名可規範如下:
- 讀別名:index-{行業}-{業務}-read
- 寫別名:index-{行業}-{業務}-insert
2.3、mapping的設計
mapping設定主要就是怎麼選擇資料型別,分詞等
中文分詞:推薦使用:"analyzer": "ik_max_word" ,這樣可以更細粒度的進行中文分詞
設定欄位的時候,務必過一下如下圖示的流程。根據實際業務需要,主要關注點:
- 資料型別選型;
- 是否需要檢索;
- 是否需要排序+聚合分析;
- 是否需要另行儲存
核心引數的含義,梳理如下
2.4、分片的設計
這個很重要,直接影響到後期的管理和效能。
Elasticsearch中的資料組織成索引。每一個索引由一個或多個分片組成。每個分片是Luncene索引的一個例項,你可以把例項理解成自管理的搜尋引擎,用於在Elasticsearch叢集中對一部分資料進行索引和處理查詢。
分片設計原則
- 推薦每個分片的大小:20-40G,建議不超過30G,但是也會有特殊的情況,有些索引欄位少,但是資料量大,這樣的話也可以增加一些分片數
- 確保每個節點的分片數量保持在低於每1GB堆記憶體對應叢集的分片在20-25之間。 因此,具有30GB堆記憶體的節點最多可以有600-750個分片
- 每個索引的分片:一般為節點數的1-3倍,假設我們有15個資料節點,則15*3*40G=1.8T,這樣一個索引最多設定真的大,如果超過了,就需要參考大索引的設計
- 分片數量儘量為資料節點的倍數,這樣就可以使得資料進來均衡,但是資料量極少的索引,根據情況進行分片數量的設計
下面寫一個簡單的參考表(都可以根據實際情況進行調整,只是個人的建議):
索引的大小 | 分片數量設定 |
0-20G | 2 |
20-100G | 8 |
100-400G | 15 |
400-900G | 30 |
900G-1.6T | 45 |
如上設定是基於15個資料節點進行配置的,基本都給增量預留了一些空間,最好是根據實際情況進行設定,如果一個索引已經很大了,上面的配置不能滿足了的話需要對對索引進行拆分了,使用索引模板+Rollover+索引生命週期進行自動滾動,拆分索引。見2.5節
2.5、大索引的設計
當一個索引太大時就會有很多的風險,首先會影響效能,當分片數一定的情況下,資料越來越多,一個分片就會越來越大,就會違背了上面的設計原則,其次就是一個索引出問題,很難恢復,並且影響範圍廣,那如何對很大的索引進行設計呢。可以使用索引模板+Rollover+生命週期進行自動滾動建立索引,所有的索引都用一個別名進行讀,並且設定一個索引為寫,這樣就能夠很好的拆分索引。先看看這麼設計的原理圖。
上面有三個索引,通過index_all索引進行檢索,是用index_latest保證只寫入到一個最新的索引中,每次索引滿足三個條件(文件數,時間,索引大小)中的一個,就會自動的滾動生成新的索引。接下來做個實操,這樣更方面理解。
先來個官網,有興趣的可以參考:https://www.elastic.co/guide/en/elasticsearch/reference/7.8/getting-started-index-lifecycle-management.html
主要分為四個步驟:
- 建立索引生命週期的規則
- 建立索引模板並應用該生命週期
- 初始化一個索引
- 驗證
首先建立生命週期的規則,對於索引的生命週期可以參考:對Elasticsearch生命週期的思考,如果資料是定期儲存的,比如一些日誌,只保留最近30天,這樣的資料結合索引的生命週期可以自動的進行清理。我們首先建立一個策略policy_index,這裡是測試,所以把時間調至5分鐘,這些配置都應該根據實際情況進行設定。
PUT _ilm/policy/policy_index
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "5m"
}
}
}
}
}
}
接下來設計索引模板,並且該策略應用進去。
PUT _index_template/policy_index_template
{
"index_patterns": [
"index-test-*"
],
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1,
"index.lifecycle.name": "policy_index", #配置策略
"index.lifecycle.rollover_alias": "index-test-insert"
},
"aliases": {
"index-test-read": {
"is_write_index": false #這個別名是用來讀的,不允許寫,否則會和寫的那個別名衝突
}
}
}
}
這裡的模板只是為了演示該小節的內容,實際情況應該把基本配置以及mapping相關的設定好
接下來就是建立一個索引了
PUT index-test-000001
建立好之後,然後給索引新增別名index-test-insert,索引就自動有了兩個別名,read負責讀,insert負責寫
接下來,只要通過驗證即可:GET index-*/_ilm/explain
最後達到條件後就會自動生成新的索引,然後把index-test-insert別名切換到新的索引上面,就是這樣子的
大索引的設計就是拆分,很多都是根據時間進行切分索引的,如果記得沒錯的話,上面的000001這些可以配置為日期的。
參考博文: