简介
众所周知,Elasticsearch的分片数是固定的,从确定下来就不可以改变了(除非reindex),但是在一些场景,比如存储 metric 的 TSDB、小数据量的日志存储,人们会期望在多分片快速写入数据以后,把老数据合并存储,节约过多的 cluster state 容量。从 5.0 版本开始,Elasticsearch 新提供了 shrink 接口,可以成倍数的合并分片数。至于rollover也是ES5.0后的一个重要功能,这个功能可以说取代了curator,实现了ES本身的生命周期管理。今天我们就好好讲讲这两个重要功能。
Shrink Index
Shrink API允许你将一个现有的索引缩减为一个具有较少主分片的新索引。目标索引中要求的主分片数量必须是源索引中分片数量的一个因素。例如,一个有8个主分片的索引可以缩减为4、2或1个主分片,或者一个有15个主分片的索引可以缩减为5、3或1。如果索引中的分片数量是一个质数,它只能被缩减为一个主分片。在缩减之前,索引中每个分片的(主分片或副本)副本必须存在于同一个节点上。
Shrink工作的原理主要如下:
- 它创建一个新的目标索引,其定义与源索引相同,但是主分片的数量较少。
- 它把源索引中的分片硬链接到目标索引中。如果文件系统不支持硬链接,那么所有的分片都被复制到新的索引中,这是一个更耗时的过程)。另外,如果使用多个数据路径,不同数据路径上的分片如果不在同一个磁盘上,就需要完整地复制段文件,因为硬链接在不同的磁盘上不起作用)
- 它恢复了目标索引,就像它是一个刚刚被重新打开的封闭索引一样。
- 这一步官当并没有提及,可选处理。可以将索引副本恢复为2,打开数据重均衡。
说了原理大家也要知道shrink需要注意的事项具体可以参考官当如下:
以下三点需要特别注意:
- 分片必须只读;
- 所有shrink的索引都必须在同一个节点;
- 集群必须是green;
下面我们进行实际的操作,操作环境为1 hot,1warm,1 cold。
代码语言:javascript复制GET _cat/nodeattrs?v
node host ip attr value
node3 192.168.248.117 192.168.248.117 rack rack3
node3 192.168.248.117 192.168.248.117 xpack.installed true
node3 192.168.248.117 192.168.248.117 box_type warm
node1 192.168.248.115 192.168.248.115 rack rack1
node1 192.168.248.115 192.168.248.115 xpack.installed true
node1 192.168.248.115 192.168.248.115 box_type cold
node2 192.168.248.116 192.168.248.116 rack rack2
node2 192.168.248.116 192.168.248.116 xpack.installed true
node2 192.168.248.116 192.168.248.116 box_type hot
Shrink Index 实验步骤
代码语言:javascript复制1.删除源和目标索引
DELETE my_source_index
DELETE my_target_index
2.创建源索引
PUT my_source_index
{
"settings": {
"number_of_shards": 6,
"number_of_replicas": 0
}
}
PUT my_source_index/_doc/1
{
"key":"yuyev1"
}
GET _cat/shards/my_source_index
# 分片数5,会失败
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 5,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
# 报错,因为没有置成 readonly
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
#将 my_source_index 设置为只读
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
# 报错,必须都在一个节点
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
DELETE my_source_index
## 确保分片都在 hot
PUT my_source_index
{
"settings": {
"number_of_shards": 6,
"number_of_replicas": 0,
"index.routing.allocation.include.box_type":"hot"
}
}
PUT my_source_index/_doc/1
{
"key":"yuyev1"
}
GET _cat/shards/my_source_index
#设置为只读
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
#成功
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
GET _cat/shards/my_target_index
# My target_index状态为也只读
PUT my_target_index/_doc/1
{
"key":"yuyev1"
}
Split 索引实验步骤
代码语言:javascript复制DELETE my_target_index
POST my_source_index/_split/my_target_index
{
"settings": {
"index.number_of_shards": 12,
"index.number_of_replicas":0
}
}
GET _cat/shards/my_target_index
# write block
PUT my_target_index/_doc/1
{
"key":"yuyev1"
}
小结一下,shrink Index和Split可以快速帮你为你的索引扩容或者缩容分片,但是对于源索引的话有:1.分片必须可读,2.所有的shrink或者split的索引分片必须在一个节点上;3.集群必须为green。同时得到的目标索引也是只读索引。
Rollover Index
当现有的索引满足你提供的条件时,rollover index API将一个别名滚动到一个新的索引。你可以使用这个API来清退一个变得太大或者太旧的索引。简单来说rollover可以根据三个条件进行对索引进行滚动,1.索引的存活时间,2.索引的最大文档数,3.最大的文件尺寸。
应用场景主要有以下三种:
1.索引文档数过大或者文件太大需要进行新索引创建和别名切换,比如我们公司的索引单个索引会按照前一天的业务量制定后一天的索引分片数,单个分片为25GB,当索引的所有分片都达到25gb的时候就会自动切换到下一个新的索引。
2.结合Index LifeCycle Management Policies一起使用。这一部分主要是ES不会自动去监控索引,只有调用rollover API才会进行进一步的监测。
下面我们进行进一步的实验说明,具体如下:
Rollover Index实验步骤
代码语言:javascript复制#Rollover API
DELETE nginx-logs*
# 不设定 is_write_true
# 名字符合命名规范
PUT /nginx-logs-000001
{
"aliases": {
"nginx_logs_write": {}
}
}
# 6次写入文档
POST nginx_logs_write/_doc
{
"log":"something"
}
POST /nginx_logs_write/_rollover
{
"conditions": {
"max_age": "1d",
"max_docs": 5,
"max_size": "5gb"
}
}
GET /nginx_logs_write/_count --数据量变成了新索引的数据量
# 查看 Alias信息
GET /nginx_logs_write
# 对应别名切换到了另一个索引
{
"nginx-logs-000002" : {
"aliases" : {
"nginx_logs_write" : { }
},
"mappings" : { },
"settings" : {
"index" : {
"creation_date" : "1625843145356",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "weIJFbKGRpm23tqlriuZMQ",
"version" : {
"created" : "7020199"
},
"provided_name" : "nginx-logs-000002"
}
}
}
}
#将别名切换的指定的索引中
DELETE apache-logs*
# 设置 is_write_index
PUT apache-logs1
{
"aliases": {
"apache_logs": {
"is_write_index":true
}
}
}
POST apache_logs/_count
POST apache_logs/_doc
{
"key":"value"
}
# 需要指定 target 的名字
POST /apache_logs/_rollover/apache-logs2
{
"conditions": {
"max_age": "1d",
"max_docs": 1,
"max_size": "5gb"
}
}
# 查看 Alias信息
GET /apache_logs
第二种方式切换后读写情况如下:
代码语言:javascript复制{
"apache-logs1": {
"aliases": {
"apache_logs": { "is_write_index": true }
}
},
"apache-logs2": {
"aliases": {
"apache_logs": { "is_write_index" : false }
}
}
}
小结一下,rollover在设置is_write_index为true的时候,不仅会保留老的索引也会保留新的索引数据,同时rollover之后还会将老的索引的is_write_index改为false,这种方式是比较推荐的。
总结
本文主要通过例子和原理讲解了Shrink,Split以及Rollover对ES索引的管理,通过本文的讲解可以让大家在生产中对ES索引管理自如。
参考
https://www.elastic.co/guide/en/elasticsearch/reference/7.1/indices-shrink-index.html#indices-shrink-index
https://www.elastic.co/guide/en/elasticsearch/reference/7.1/indices-rollover-index.html