
創作人:楊松柏
了解 Elasticsearch 的同學應該都知道,索引的主分片在設定之後,改變(
shrink
,
split
reindex
)主分片數目的成本相當大;是以在設計之初,一定要規劃好索引的分片數目。如果叢集的中節點數目固定,且寫入的資料不會再有更新操作或者更新操作極其少;可以使用
Rollover index
的方式來限制每個索引的大小。
Rollover:
若
rollover-target
綁定的目前索引滿足設定的條件,執行滾動操作将會為
rollover-target
建立新索引。滾動目标可以是索引别名或者資料流;
- 當滾動目标是别名時,執行滾動别名将指向新的索引。
- 當滾動目标是資料流時,資料流将資料寫入到新的索引,且新索引名字尾自增 1。
POST /alias1/_rollover/my-index-000002
{
"conditions": {
"max_age": "7d",
"max_docs": 2,
"max_size": "5gb"
}
}
如果需要實作 Rollover 自動化,可以自行實作一個定時任務請求該 API 或者使用 Elasticsearch 的 index lifecycle management (ILM) 功能。
API 介紹
Rollover API
POST /<rollover-target>/_rollover/<target-index>?wait_for_active_shards=<number>
POST /<rollover-target>/_rollover?wait_for_active_shards=<number>
URI 參數
必填參數,參數類型
string
。将已存的索引别名或資料流,配置設定給目标索引,來完成執行滾動。
可選參數,參數類型
string
。代表要被建立和配置設定索引别名的目标索引名稱;
目标索引名稱必須遵循以下規則:
- 所有字元必須小寫
- 不允許包含
,\
/
*
?
"
<
>
|
(space character)
,
#
- 在7.0版本之前允許包含:,在7.0+不再支援
- 不能夠以
-
_
開頭+
- 名稱不能夠是
或者.
..
- 長度不能超過 255 位元組(注意:這是位元組數限制,如果是字元得看表示一個字元需要多少個位元組)
- 名稱以
開頭已經過時;除了隐藏索引和由插件管理的内部索引.
如果
rollover-target
為資料流,
<target-index>
參數是不被允許的;執行 Rollover 資料流會按照相應規則生産新的索引:格式為
.ds-<rollover-target>-000001
,其中
-000001
,數字必為6位數,左側高位用
補充,每發生一次 Rollover 自增加1。
rollover-target
為一個索引别名,且别名綁定的索引以
-<number>
結尾;如果不指定
<target-index>
執行 Rollover ,将生成新的索引
indexName-<number>+1
。
如果别名現綁定的索引名稱不滿足以
-<number>
形式結尾,則必須指定
<target-index>
查詢參數
dry_run
可選參數,參數類型為
boolean
,預設值為 false。該參數的作用為檢測 index 是否滿足提供的 rollover 條件。 如果設定為true,将會完成檢查工作,但不會真正執行 rollover 。
include_type_name
boolean
,預設值為 false。在
mappings
體内要求必須有mapping type。
wait_for_active_shards
string
,預設值為 1(即隻要一個主分片處于活躍便可以執行操作)。在執行
rollover
,要求處于活躍狀态的索引分片副本數目,以保證資料的可靠和安全性;設定為
all
或任何正整數,最多為索引分片的總數(
number_of_replicas+1
)。
詳情可以參考 Active shards: https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-index_.html#index-wait-for-active-shards
master_timeout
可選參數,
value
值的機關可為
d
、
h
m
s
ms
micros
nanos
,預設值為
30s
。 等待連接配接到主節點的時間。如果在逾時時間門檻值之前沒有收到響應,則請求失敗并傳回錯誤。
timeout
可選參數,value 值的機關可為
d
h
m
s
ms
micros
nanos
30s
。請求等待響應的時間。如果在逾時時間門檻值之前沒有收到響應,則請求失敗并傳回錯誤。
請求體參數
aliases
alias object。包含索引的 Index aliases。詳情可以參看索引别名,批量操作的相關内容(即_aliases API)。
conditions
可選參數,參數類型
object
。如果設定條件,則隻有現有索引達到條件集任何一個條件的門檻值才會完成
rollover
。如果省略,則無條件執行
rollover
。條件集包括:
- max_age
d
h
m
s
ms
micros
;依據索引的建立時間與現在時間內插補點作為門檻值。nanos
- max_docs
;索引的最大文檔數目;計數不包括自上次integer
之後新添加的文檔和副本分片的文檔。refresh
-
max_size
可選參數, byte units 值(機關
b
kb
mb
gb
tb
)。索引大小的最大值,隻計算索引主分片的大小,副本不包括在内。pb
mappings
可選參數,參數 mapping object。為索引進行資料模組化,定義字段
schema
等。如果設定,
mapping
可能包含:
- 字段名字(Field names)
- 字段的資料類型(Field data types)
-
mapping中一些修飾參數(Mapping parameters)
settings
可選參數,參數 index setting object。索引的配置選項;比如設定滾動産生的新索引副本分片數目等等。
詳情可以參看 Index Settings: https://www.elastic.co/guide/en/elasticsearch/reference/7.11/index-modules.html#index-modules-settings
Rollover的分類
依據不同
rollover target
和别名情況,可以簡單的分為三種執行情況:
别名隻綁定一個索引
rollover target
為别名,且别名和索引一對一關系;滾動請求過程如下:
- 建立一個新索引
- 給新索引添加别名
- 将别名與之前綁定索引的關聯關系移除
别名綁定多個索引
rollover target
為别名,且與多個索引建立了綁定關系,隻有其中一組的綁定關系
**is_write_index**
的值為
true
(如果對
**is_write_index**
有疑問,請參看索引别名小節)。在這種情況下,滾動請求過程如下:
- 新索引于别名的綁定時,将
設定為is_write_index
true
- 修改别名與舊索引的綁定關系,将
is_write_index
false
rollover-target 為資料流
rollover target
為資料流,滾動請求過程如下:
- 在資料流上添加新索引作為備份索引和寫索引
- 增加資料流的
屬性generation
實戰示例
基礎示例
别名與索引是一對一關系,執行 _rollover 之後,别名将關聯到新的索引
PUT /logs-1 #備注1
{
"aliases": {
"logs_write": {}
}
}
# Add > 2 documents to logs-1
PUT logs-1/_bulk
{"index":{}}
{"user.id":"kimchy"}
{"index":{}}
{"user.id":"tom"}
POST /logs_write/_rollover #備注2
{
"conditions": {
"max_age": "7d",
"max_docs": 2,
"max_size": "5gb"
}
}
建立索引
logs-1
且與别名
logs_write
綁定.
logs_write
指向的索引滿足條件集中的任何一個條件(索引“年齡值”>=7天或者主分片文檔數目>=2或者主分片 size>=5gb);則
logs-000002
将會被建立,且别名
logs_write
将更新綁定到
logs-000002
如上代碼塊 Rollover API 傳回值如下
{
"acknowledged": true,
"shards_acknowledged": true,
"old_index": "logs-1",
"new_index": "logs-000002",
"rolled_over": true, #索引是否執行了滾動
"dry_run": false, # 是否為 dry_run 模式
"conditions": { # 條件集觸發結果
"[max_age: 7d]": false,
"[max_docs: 2]": true,
"[max_size: 5gb]": false,
}
}
通過檢視索引與别名的綁定關系,可以看到
logs_write
隻綁定
logs-000002
# 檢視指令
GET _cat/aliases/logs_write?v
#傳回值如下
alias index filter routing.index routing.search is_write_index
logs_write logs-000002 - -
基于資料流滾動
資料流必須要提前設定一個索引模闆,否則無法建立資料流。
PUT _index_template/template
{
"index_patterns": ["my-data-stream*"],
"data_stream": { }
}
建立資料流
PUT /_data_stream/my-data-stream # 備注1
建立一個名為
my-data-stream
的資料流,并且初始化一個名字為
my-data-stream-000001
的
backing
索引。
檢視
GET /_data_stream/my-data-stream
。傳回值如下
{
"data_streams" : [
{
"name" : "my-data-stream",
"timestamp_field" : {
"name" : "@timestamp"
},
"indices" : [
{
"index_name" : ".ds-my-data-stream-000001",
"index_uuid" : "Vir6yRm4S42k8n22mZ5YBw"
}
],
"generation" : 1,
"status" : "GREEN",
"template" : "my-index-template",
"ilm_policy" : "my-lifecycle-policy"
}
]
}
插入資料,然後執行滾動
# Add > 2 documents to my-data-stream
#為了能夠實時的看到效果插入資料時,加上 refresh 參數
PUT my-data-stream/_bulk?refresh
{ "create":{ } }
{ "@timestamp": "2099-05-06T16:21:15.000Z", "message": "192.0.2.42 - - [06/May/2099:16:21:15 +0000] \"GET /images/bg.jpg HTTP/1.0\" 200 24736" }
{ "create":{ } }
{ "@timestamp": "2099-05-06T16:25:42.000Z", "message": "192.0.2.255 - - [06/May/2099:16:25:42 +0000] \"GET /favicon.ico HTTP/1.0\" 200 3638" }
{ "create":{ } }
{ "@timestamp": "2099-05-06T16:27:42.000Z", "message": "192.0.2.255 - - [06/May/2099:16:25:42 +0000] \"GET /favicon.ico HTTP/1.0\" 200 3638" }
POST /my-data-stream/_rollover #備注1
{
"conditions" : {
"max_age": "7d",
"max_docs": 2,
"max_size": "5gb"
}
}
如果目前的寫資料索引滿足條件集中的任何一個條件;則滾動目标将建立一個新的
backing
索引
my-data-stream-000002
,且新的
backing
索引将作為寫入資料的索引。
上面代碼塊的 Rollover API 傳回值如下:
{
"acknowledged" : false,
"shards_acknowledged" : false,
"old_index" : ".ds-my-data-stream-000001",#資料流之前對應的寫資料索引
"new_index" : ".ds-my-data-stream-000002",,#資料流新對應的寫資料索引
"rolled_over" : true,#索引是否執行滾動
"dry_run" : false, # 是否為 dry_run 模式
"conditions" : { # 滾動條件集,集觸發情況
"[max_size: 5gb]" : false,
"[max_docs: 2]" : true,
"[max_age: 7d]" : false
}
}
再次檢視資料流
{
"data_streams" : [
{
"name" : "my-data-stream", # 資料流名稱
"timestamp_field" : {
"name" : "@timestamp"
},
"indices" : [
{
# backing索引
"index_name" : ".ds-my-data-stream-000001",
"index_uuid" : "Vir6yRm4S42k8n22mZ5YBw"
},
{
"index_name" : ".ds-my-data-stream-000002",
"index_uuid" : "WcctdbIqSMqk3MmefRdfDQ"
}
],
"generation" : 2, #目前是那一個版本的後備索引作為寫索引
"status" : "GREEN",
"template" : "my-index-template", # 适配的索引模闆
"ilm_policy" : "my-lifecycle-policy"
}
]
}
也可以通過 Kibana 進行檢視
目标索引設定 setting
新索引的
setting
mapping
和
aliases
可以取自索引名比對的任何索引模闆。如果
<rollover-target>
為索引别名,你可以在
rollover API
的請求體中指定
settings
mappings
aliases
,與建立索引的API(create index API)類似。如果請求體指定的值優先于比對的索引模闆。
如下示例重寫了 index.number_of_shards setting:
PUT /logs-000001
{
"aliases": {
"logs_write": {}
}
}
POST /logs_write/_rollover
{
"conditions" : {
"max_age": "7d",
"max_docs": 2,
"max_size": "5gb"
},
"settings": {
"index.number_of_shards": 2
}
}
指定目标索引名稱
<rollover-target>
是索引别名,并且綁定的索引名稱以
-<number>
結尾;如果不指定目标索引,發生滾動時生成的新索引名稱為 indexName-6 位數字,每滾動一次數字自增一次。
例如索引為
logs-1
(或者
logs-000001
),執行滾動後新的索引名字為
logs-000002
,6位數字低位自增高位補 0。
如果舊的索引名稱不滿足
indexName-<number>
結尾,則執行滾動必須指定新索引名字;
示例如下:
# my_alias綁定的索引索引名稱不滿足indexName-<number>格式
#必須指定索引my_new_index_name
POST /my_alias/_rollover/my_new_index_name
{
"conditions": {
"max_age": "7d",
"max_docs": 2,
"max_size": "5gb"
}
}
基于 date math 滾動
<rollover-target>
是索引别名,使用 date math 根據索引滾動的目前日期來命名滾動索引;在某些場景中是非常有用的,比如定時按天删除索引、按天查詢資料等。rollover API 支援 date math,但是要求索引名稱必須以日期
-<number>
結尾,
例如:
logstash-2021.05.06-1
;以這種格式命名的主要是友善在任何時候執行滾動,索引名稱自增。
# PUT /<logs-{now/d}-1> with URI encoding:
PUT /%3Clogs_%7Bnow%2Fd%7D-1%3E #備注1
{
"aliases": {
"logs_write": {}
}
}
PUT logs_write/_doc/1
{
"message": "a dummy log"
}
POST logs_write/_refresh
# 立即執行 _rollover
POST /logs_write/_rollover #備注2
{
"conditions": {
"max_docs": 1,
"max_age": "1d",
"max_size": "5gb"
}
}
建立一個索引取今天的日期,
logs_2021.05.06-1
執行滾動操作,如果立即執行,則新索引名為
logs_2021.05.06-000002
;如果等到24小時之後執行索引名稱為
logs_2021.05.07-000002
你可以按照 date math 文檔的說明去使用這些索引。
例如,你需要搜尋過去三天索引的資料,你可以按照如下的書寫方式:
# GET /<logs-{now/d}-*>,<logs-{now/d-1d}-*>,<logs-{now/d-2d}-*>/_search
GET /%3Clogs-%7Bnow%2Fd%7D-*%3E%2C%3Clogs-%7Bnow%2Fd-1d%7D-*%3E%2C%3Clogs-%7Bnow%2Fd-2d%7D-*%3E/_search
Dry run
rollover API
支援
dry_run
模式,該模式主要用于條件檢測。比如想檢測索引是否滿足設定的條件完成滾動。
POST /logs_write/_rollover?dry_run
{
"conditions" : {
"max_age": "7d",
"max_docs": 1000,
"max_size": "5gb"
}
}
傳回值如下:
{
"acknowledged" : false,
"shards_acknowledged" : false,
"old_index" : "logs-000002", #目前索引
"new_index" : "logs-000003",# 将要新生成的索引
"rolled_over" : false, #是否完成滾動
"dry_run" : true, # 是否為檢測模式
"conditions" : {
"[max_size: 5gb]" : false,
"[max_docs: 1000]" : false,
"[max_age: 7d]" : false
}
}
基于 write index 滾動
基于
write index
滾動主要是為了解決,使用别名查詢能夠擷取到之前建立的索引資料,以及同一别名綁定多個索引滾動切換歧義問題。同一個别名具有查詢和寫入兩種特性。
示例如下
#建立一個索引,綁定别名 logs,并标注 is_write_index 為 true,即通過别名寫入資料,實際是寫入到 my_logs_index-000001 表中
PUT my_logs_index-000001
{
"aliases": {
"logs": { "is_write_index": true }
}
}
#寫入一個文檔
PUT logs/_doc/1
{
"message": "a dummy log"
}
#重新整理,生成一個 segements,使文檔變得可搜尋
POST logs/_refresh
#執行滾動操作
POST /logs/_rollover #備注1
{
"aliases": {"search_all": {}}, #備注2
"conditions": {
"max_docs": "1"
}
}
#再次基于别名寫入
PUT logs/_doc/2
{
"message": "a newer log"
}
執行滾動操作
write index
切換成為新建立的索引,之後寫入的資料将寫入到新索引中,滾動時新産生的索引添加别名
search_all
上述代碼塊執行
_rollover
的傳回值如下
{
"_index" : "my_logs_index-000002",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
在完成滾動之後,
GET _alias/logs
,檢視别名元資訊,可以發現新索引已經作為
write index
{
"my_logs_index-000002": {
"aliases": {
"logs": { "is_write_index": true }
}
},
"my_logs_index-000001": {
"aliases": {
"logs": { "is_write_index" : false }
}
}
}
基于 ILM 實作自動 Rollover
首先在 Kibana ,定義生命周期政策(也可通過 API 方式);
下圖規定了 Hot 階段重新生成索引的規則,這部分功能其實就是對于
rollover API
的封裝;下圖中我們定義了一個名稱為
rollover-test-all
的生命周期管理政策,其中滾動條件為
max_size
,為 20gb,
max_age
為 1 天,
max_docs
為 2;
我們可以通過 API,檢視
GET _ilm/policy/rollover-test-all
。傳回值如下:
{
"rollover-test-all" : {
"version" : 1,
"modified_date" : "2021-05-11T15:23:27.155Z",
"policy" : {
"phases" : {
"hot" : {
"min_age" : "0ms",
"actions" : {
"rollover" : {
"max_size" : "20gb",
"max_age" : "1d",
"max_docs" : 2
},
"set_priority" : {
"priority" : 100
}
}
}
}
}
}
}
建立一個模闆,模版中引用剛才定義的生命周期政策,并指定滾動的别名。
關于索引模闆更多資訊請參看 Simulate multi-component templates
# 這個是 legacy 的 index template,适用于 7.8 版本以前,
# 但在7.11版本,仍然可以用
PUT _template/iml-rollover_template
{
"index_patterns": [
"iml-rollover*"
],
"aliases": {
"iml-rollover_alias": {}
},
"settings": {
"index": {
"lifecycle": {
"name": "rollover-test-all",
"rollover_alias" : "iml-rollover_write_alias"
},
"refresh_interval": "2s",
"number_of_shards": "1",
"number_of_replicas": "0"
}
},
"mappings": {
"properties": {
"name": {
"type": "keyword"
}
}
}
}
# 7.8 版本之後,可以使用 _index_template 定義模闆;
PUT _index_template/iml-rollover_template
{
"index_patterns": ["iml-rollover*"],
"template": {
"settings": {
"lifecycle": {
"name": "rollover-test-all",
"rollover_alias" : "iml-rollover_write_alias"
},
"refresh_interval": "2s",
"number_of_shards": "1",
"number_of_replicas": "0"
},
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"name": {
"type": "keyword"
}
}
},
"aliases": {
"iml-rollover_alias": { }
}
},
"priority": 500,
"_meta": {
"description": "my custom rollover test"
}
}
PUT iml-rollover-000001
{
"aliases": {
"iml-rollover_write_alias": { "is_write_index": true }
}
}
插入資料
PUT iml-rollover_write_alias/_bulk?refresh=true
{"index":{}}
{"name":"kimchy"}
{"index":{}}
{"name":"tom"}
檢視索引情況
GET _cat/indices/iml-rollover-*?v&h=health,index,docs.count
結果如下
health index docs.count
green iml-rollover-000001 2
green iml-rollover-000002 0
iml-rollover-000001 的文檔個數為 2,并且 iml-rollover-000002 索引已經被建立。檢視别名的關聯關系
GET _cat/aliases/iml-rollover_*?format=json
。索引 iml-rollover-000002 的别名 iml-rollover_write_alias 被标記為具有寫權限。
[
{
"alias" : "iml-rollover_alias",
"index" : "iml-rollover-000001",
"filter" : "-",
"routing.index" : "-",
"routing.search" : "-",
"is_write_index" : "-"
},
{
"alias" : "iml-rollover_write_alias",
"index" : "iml-rollover-000001",
"filter" : "-",
"routing.index" : "-",
"routing.search" : "-",
"is_write_index" : "false"
},
{
"alias" : "iml-rollover_alias",
"index" : "iml-rollover-000002",
"filter" : "-",
"routing.index" : "-",
"routing.search" : "-",
"is_write_index" : "-"
},
{
"alias" : "iml-rollover_write_alias",
"index" : "iml-rollover-000002",
"filter" : "-",
"routing.index" : "-",
"routing.search" : "-",
"is_write_index" : "true"
}
]
和預期是一緻的,正确的完成滾動。這時通過
iml-rollover_write_alias
寫入資料,資料被寫入到
iml-rollover-000002
索引中。再次執行插入資料語句,然後檢視索引文檔。
health index docs.count
green iml-rollover-000001 2
green iml-rollover-000002 2