Elasticsearch:Searchable snapshot 在索引生命周期管理中的应用

这是继上一篇文章 “Elasticsearch:Searchable snapshot - 可搜索的快照” 的第二篇关于 searchable snapshot 文章。在上一篇文章中,我提到使用 search snapshot 的两个应用场景:

  • 通过 mount snapshot API 来实现
  • 通过 ILM 自动完成。 当可搜索快照操作达到冷或冻结阶段时,它将自动将常规索引转换为可搜索快照索引

第一种方式,我已经在上述文章中已经展示了。 在今天的文章中,我将展示如何在索引生命周期中使用 searchable snapshot。在索引生命周期管理中,我们可以在 cold 阶段自动地引入 searchable snapshot,从而达到节省成本的目的。

 

安装

如果你有 Elastic cloud 的账号或者其它云部署,你可以省去这一步。在今天的展示中,我们将使用一个本地部署的 Elasticsearch 集群来进行展示。我们可以参阅之前的文章 “Elastic:Data tiers 介绍及索引生命周期管理 - 7.10 之后版本” 来安装我们的 Elasticsearch。简单地说,我们参阅文章 “如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch” 下载 Elasticsearch,并解压缩到一个目录中。然后,我们在用户的 home 目录中创建一个如下的目录:

mkdir -p shared_folder/my_repo/

然后我们修改 Elasticsearch 的配置文件 config/elasticsearch.yml:

config/elasticsearch.yml

path.repo: <Your home>/shared_folder/my_repo

你需要把你的电脑上的路径替换上面的 path.repo。针对我的情况:

path.repo: /Users/liuxg/shared_folder/my_repo

我们把上面的这句话添加到 elasticsearch.yml 文件中去。然后,打开一个 terminal,并在 Elasticsearch 的安装根目录中打入如下的命令:

./bin/elasticsearch -E node.name=node1 -E node.roles=data_hot,data_content,master,ingest -Enode.max_local_storage_nodes=2

上面的命令创建一个名字叫做 node1 的数据层为 data_hot 的节点。我们在另外一个 terminal 中,在同一个安装的 Elasticsearch 安装根目录中打入如下的命令:

./bin/elasticsearch -E node.name=node2 -E node.roles=data_cold,data_content,master,ingest -Enode.max_local_storage_nodes=2

在上面,它运行了一个叫做 node2 的数据层为 data_cold 的节点。这样我们的 Elasticsearch 集群就有两个节点:一个是 data_hot,而另外一个是 data_cold。

接下来,我们按照文章 “Kibana:如何在 Linux,MacOS 及 Windows上安装 Elastic 栈中的 Kibana” 安装好 Kibana。

我们可以在 Kibana 中打入如下的命令:

GET _cat/nodes?v

上面命令显示的结果为:

ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1           58         100   9    2.10                  hims      *      node1
127.0.0.1           17         100   9    2.10                  cims      -      node2

上面的 hims 的意思是:data_hot,master,ingest,而 cims 中 c 指的是 data_cold。显然我们的两个节点的 Elasticsearch 集群已经起来了。

 

开启试用许可

当我们使用 searchable snapshot 时,它是一个订阅的功能。我们需要在 Stack Management 中启动试用许可:

 

注册 snapshot 仓库

我们运行如下的命令来创建一个叫做 my_local_repo 的 snapshot 仓库。这个在 ILM 的 policy 创建中将被使用:

PUT _snapshot/my_local_repo
{
  "type": "fs",
  "settings": {
    "location": "<Your home>/shared_folder/my_repo"
  }
}

在上面,你需要依据你自己电脑上的路径修改上面的 location 参数。

 

创建 ILM 策略

我们需要创建一个 ILM 策略:

在上面,我们定义了 rollover 的条件:

  • 当文档的大小超过 50G
  • 当文档的数量超过 5 个文档
  • 当文档在 hot phase 的时间超过 30 天

当其中的任何一个条件满足时,那么 rollover 将会发生。接下来,我们来定义 cold phase:

在上面,我们定义 searchable snapshot 仓库为 my_local_repo。点击  Save policy。我们可以在 Kibana 中使用如下的命令来进行查看:

GET _ilm/policy/searchable-snapshot-demo

上面的命令返回的结果为:

{
  "searchable-snapshot-demo" : {
    "version" : 2,
    "modified_date" : "2021-04-27T05:22:29.253Z",
    "policy" : {
      "phases" : {
        "cold" : {
          "min_age" : "0d",
          "actions" : {
            "searchable_snapshot" : {
              "snapshot_repository" : "my_local_repo",
              "force_merge_index" : true
            },
            "set_priority" : {
              "priority" : 0
            }
          }
        },
        "hot" : {
          "min_age" : "0ms",
          "actions" : {
            "rollover" : {
              "max_size" : "50gb",
              "max_age" : "30d",
              "max_docs" : 5
            },
            "set_priority" : {
              "priority" : 100
            }
          }
        }
      }
    }
  }
}

从上面我们可以看出来,在 searchable_snapshot 中,它定义了 "force_merge_index" : true。这个对于提升 searchable snapshot 的速度非常有用。在上面,我们实现了 Hot phase => Cold phase 的迁移,如果条件满足的话。为了说明问题的方便,我们省去了 Warm phase。

因为 ILM 是在每隔一个时间间隔来进行检查的,为了下面的展示方便,我把检查的时间定义为每隔10秒:

PUT _cluster/settings
{
    "transient": {
      "indices.lifecycle.poll_interval": "10s"
    }
}

这样我们就完成了 ILM 策略的定义。

 

定义 index template

我们在 Kibana 的 console 中输入如下的命令:

# Create tje template to apply the policy to every new backing index of the data stream
PUT _index_template/template_demo
{
  "index_patterns": ["demo-*"],
  "data_stream": {},
  "priority": 200,
  "template": {
    "settings": {
      "number_of_shards": 1,
      "auto_expand_replicas": "0-1",
      "index.lifecycle.name": "searchable-snapshot-demo",
      "index.routing.allocation.include._tier_preference": "data_hot"
    }
  }
}

在上面,我们定义了一个叫做 template_demo 的 index template。也就是当任何索引的名字符合 demo-*,那么这个 index template 里的设置将会自动起作用。在这里,我们定义了一个 data_stream。在 template 里,我们定义了 index.lifecycle.name。它使用我们刚才定义的 ILM policy searchable-snapshot-demo。当我们的数据被导入时,将会在 data_hot 的节点进行处理。

 

创建一个 data stream

创建一个  data stream 是非常简单的:

# Create a data stream
PUT _data_stream/demo-ds

运行上面的命令。由于我们在上面已经创建了以 demo-* 为 index_pattern 的 index template,所以上面的创建是成功的。否则如果我们用如下的命令:

PUT _data_stream/demo

它将会是失败的。错误代码告诉你没有相对应的 index template。

# Check the shards allocation
GET _cat/shards/demo-ds?v

上面的命令显示:
 

index                         shard prirep state   docs store ip        node
.ds-demo-ds-2021.04.27-000001 0     p      STARTED    0  208b 127.0.0.1 node1

从上面我们可以看出来,新生成的索引在 node1 上,也就是我们的 data_hot 节点。我们使用如下的命令来检查索引:

# Verify data stream indexes
GET _data_stream/demo-ds
{
  "data_streams" : [
    {
      "name" : "demo-ds",
      "timestamp_field" : {
        "name" : "@timestamp"
      },
      "indices" : [
        {
          "index_name" : ".ds-demo-ds-2021.04.27-000001",
          "index_uuid" : "6XomEKlRTq22hB1nyau78w"
        }
      ],
      "generation" : 1,
      "status" : "GREEN",
      "template" : "template_demo",
      "ilm_policy" : "searchable-snapshot-demo",
      "hidden" : false
    }
  ]
}

 

导入数据

接下来,我们可以开始导入我们的数据了:

PUT _ingest/pipeline/add-timestamp
{
  "processors": [
    {
      "set": {
        "field": "@timestamp",
        "value": "{{_ingest.timestamp}}"
      }
    }
  ]
}

POST demo-ds/_doc?pipeline=add-timestamp
{
  "user": {
    "id": "liuxg"
  },
  "message": "This is so cool!"
}

在上面,我们使用一个 pipeline 来添加一个 timestamp。我们执行上面的 POST 命令 7 七次,这样我们就创建了7个文档,从而满足大于5个文档的条件。rollover 将发生。我们可以看到如下的结果:

{
  "_index" : ".ds-demo-ds-2021.04.27-000001",
  "_type" : "_doc",
  "_id" : "LGnBEXkBugydd_Q0zaSO",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 6,
  "_primary_term" : 1
}

上面说明数据都是写入到 .ds-demo-ds-2021.04.27-000001 中去的。我们可以使用如下的命令来查看当前的 ILM 状态:

GET demo-ds/_ilm/explain
{
  "indices" : {
    ".ds-demo-ds-2021.04.27-000002" : {
      "index" : ".ds-demo-ds-2021.04.27-000002",
      "managed" : true,
      "policy" : "searchable-snapshot-demo",
      "lifecycle_date_millis" : 1619501034528,
      "age" : "6.18s",
      "phase" : "hot",
      "phase_time_millis" : 1619501036441,
      "action" : "rollover",
      "action_time_millis" : 1619501037520,
      "step" : "check-rollover-ready",
      "step_time_millis" : 1619501037520,
      "phase_execution" : {
        "policy" : "searchable-snapshot-demo",
        "phase_definition" : {
          "min_age" : "0ms",
          "actions" : {
            "rollover" : {
              "max_size" : "50gb",
              "max_age" : "30d",
              "max_docs" : 5
            },
            "set_priority" : {
              "priority" : 100
            }
          }
        },
        "version" : 2,
        "modified_date_in_millis" : 1619500949253
      }
    },
    ".ds-demo-ds-2021.04.27-000001" : {
      "index" : ".ds-demo-ds-2021.04.27-000001",
      "managed" : true,
      "policy" : "searchable-snapshot-demo",
      "lifecycle_date_millis" : 1619501034494,
      "age" : "6.21s",
      "phase" : "cold",
      "phase_time_millis" : 1619501037791,
      "action" : "searchable_snapshot",
      "action_time_millis" : 1619501038333,
      "step" : "wait-for-shard-history-leases",
      "step_time_millis" : 1619501038333,
      "phase_execution" : {
        "policy" : "searchable-snapshot-demo",
        "phase_definition" : {
          "min_age" : "0d",
          "actions" : {
            "searchable_snapshot" : {
              "snapshot_repository" : "my_local_repo",
              "force_merge_index" : true
            },
            "set_priority" : {
              "priority" : 0
            }
          }
        },
        "version" : 2,
        "modified_date_in_millis" : 1619500949253
      }
    }
  }
}

 从上面,我们可以看到两个 phase:hot 及 cold。我们可以通过如下的命令来查看所有的索引:

GET _cat/indices

上面的命令显示:

green open .ds-demo-ds-2021.04.27-000002          yrYjvXelQmy1rMtnW7LJuw 1 0     0    0    208b    208b
green open .kibana_task_manager_7.12.0_001        wsyiF-q3T728L5iOV6YyRA 1 1     9 2915 956.2kb 554.5kb
green open restored-.ds-demo-ds-2021.04.27-000001 hTo6C5jkSC-2vcq4yZ05eg 1 0     7    0   5.9kb   5.9kb
green open .apm-custom-link                       pTXXdpKOSnybUgPAPwYzjQ 1 1     0    0    416b    208b
green open .apm-agent-configuration               hVHPkXnMRjaXUV4lRqJHCQ 1 1     0    0    416b    208b
green open kibana_sample_data_logs                VikGPyZ2Rg22Z-9Jk6Blcw 1 1 14074    0  19.6mb   9.8mb
green open .kibana_7.12.0_001                     cVFoWm1zRMu-2jwYANAALQ 1 1   164  266   8.8mb   4.4mb
green open .kibana-event-log-7.12.0-000001        gHuh-Kf4QA-uVTXOLwCFHg 1 1     8    0  86.9kb  43.4kb
green open twitter1                               vcmlfo9KRkeS2VJEZ1TGgg 1 1     6    0  24.8kb  12.4kb
green open .tasks                                 vTmHk4ClTaqIcdPtTchs3w 1 1    12    0  50.5kb  25.2kb

在上面,我们可以看到 .ds-demo-ds-2021.04.27-000002 及 restored-.ds-demo-ds-2021.04.27-000001 两个索引。我们可以分别查看它们当中的文档:

GET .ds-demo-ds-2021.04.27-000002/_count
{
  "count" : 0,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  }
}

上面显示的结果为0。当我们重新写入一个文档时,那么它将写入到 .ds-demo-ds-2021.04.27-000002 索引中。

GET restored-.ds-demo-ds-2021.04.27-000001/_count

它显示:

{
  "count" : 7,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  }
}

也就是是说所有的文档都可以通过访问 restored-.ds-demo-ds-2021.04.27-000001 来获得。这个索引就是通过 searchable snapshot 来实现的。

GET /_cat/shards/.ds-demo-ds-2021.04.27-000002/?v&h=index,shard,prirep,state,docs,store,node

上面的命令显示:

index                         shard prirep state   docs store node
.ds-demo-ds-2021.04.27-000002 0     p      STARTED    0  208b node1

而我们使用如下的命令:

GET /_cat/shards/restored-.ds-demo-ds-2021.04.27-000001/?v&h=index,shard,prirep,state,docs,store,node

它显示:

index                                  shard prirep state   docs store node
restored-.ds-demo-ds-2021.04.27-000001 0     p      STARTED    7 5.9kb node2

上面的命令显示有7个文档。

GET /_cat/recovery/restored-.ds-demo-ds-2021.04.27-000001/?v&h=index,time,type,stage,files_percent,bytes_recovered,bytes_percent

上面的命令显示:

index                                  time  type     stage files_percent bytes_recovered bytes_percent
restored-.ds-demo-ds-2021.04.27-000001 693ms snapshot done  100.0%        4751            100.0%

它显示类型是 snapshot,并且是100%数据可以使用的。

我们可以通过如下的命令来查询所有的文档:

GET demo-ds/_search

上面的命令将显示7个文档:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 7,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "restored-.ds-demo-ds-2021.04.27-000001",
        "_type" : "_doc",
        "_id" : "U2nIEXkBugydd_Q0i6RB",
        "_score" : 1.0,
        "_source" : {
          "@timestamp" : "2021-04-27T05:23:46.113665Z",
          "message" : "This is so cool!",
          "user" : {
            "id" : "liuxg"
          }
        }
      },
      {
        "_index" : "restored-.ds-demo-ds-2021.04.27-000001",
        "_type" : "_doc",
        "_id" : "WGnIEXkBugydd_Q0m6QX",
        "_score" : 1.0,
        "_source" : {
          "@timestamp" : "2021-04-27T05:23:50.166958Z",
          "message" : "This is so cool!",
          "user" : {
            "id" : "liuxg"
          }
        }
      },
 ...

虽然我们文档的存储是在 snapshot 里,但是我们还是可以对它进行搜索,感觉它就像我们正常使用的一个索引一样。通过 searchable snapshot 的引入,我们可以把存储的成本几乎降下一半。

已标记关键词 清除标记
相关推荐