作者:刘晓国
Elasticsearch 提供了 replica 解决方案,它可以帮我们解决了如果有一个或多个 node 失败了,那么我们的数据还是可以保证完整的情况,并且搜索还可以继续进行。但是,有一种情况是我们的所有的 node,或者有一部分 node 失败,可能会造成我们的数据的丢失。也就是说 replca 不能提供一种灾难性的保护机制。我们需要一种完整的备份机制。
Snapshot 及 Restore
在 Elastic 里,我们提供了一个叫做 snapshot 及 restore API 的接口。使您可以使用数据和状态快照备份您的 Elasticsearch 索引和集群。 快照很重要,因为快照会在出现问题时提供您数据的副本。 如果需要回滚到旧版本的数据,则可以从存储库中还原快照。
如上图所示,我们可以把当前 index 的状态及数据存入到一个 repository 里去。
当我们做 snapshot 时,我们可以看到:
在上面,我们可以看到 Snapshot_1 是第一个 snapshot,它指向 _0, _1,_2, 及 _3 这些 segments。之后的 Snapshot_2 是第二个 snapshot,它指向之前的 _0, _1, _2 segment,但是 _3 由于一些原因 _3 在 Snapshot_2 发生时,不存在,所以就没有包含在 Snapshot_2 里,同时由于之前的 Snapshot_1 已经含有 _0, _1, _2,那么 Snapshot_2 就不用备份这些 segement 了,它备份最新的 _4 segment。综上所述,snapshot 是增量的,它只保存从上次 snapshot 过后的变化。在通常的情况下,每隔 30m 来保存快照是足够的。
当我们删除一个 snapshot 时:
当我们删除 Snapshot_1 时,我们也值删除了 _3 这个不存在的 segement。
Repository
为了能够做备份,我们首先必须创建一个 repository,也就是一个仓库。你可以为一个 cluster 创建多个仓库。目前支持的仓库类型有:
这里需要注意的是: S3, HDFS, Azure and GCS 需要相应的插件进行安装才可以。
注册仓库
在一个 snapshot 可以被使用之前,我们必须注册一个仓库(repository)。
使用 _snapshot 终点
文件夹必须对所有的 node 可以访问
path.repo 必须在所有的 node 上进行配置,针对一个 fs 的 repository 来说
PUT _snapshot/my_repo { "type": "fs", "settings": { "location": "/mnt/my_repo_folder" } }
这里 /mnt/my_repo_folder 必须加进所有 node 的 elasticsearch.yml 文件中。
fs resposity 设置:
PUT _snapshot/my_repo { "type": "fs", "settings": { "location": "/mnt/my_repo_folder", "compress": true, "max_restore_bytes_per_sec": "35mb", "max_snapshot_bytes_per_sec": "35mb" } }
这里,我们定义 compress 为 true,表明我们希望压缩。通过 max_restore_bytes_per_sec 及 max_snapshot_bytes_per_sec 的定义,我们可以来限制数据的 snapshot 及恢复的数据速度。
S3 repository 设置
为了能能使用 S3 仓库,我们必须使用如下的命令来进行安装插件:
./bin/elasticsearch-plugin install repository-s3
注意,上面的命令必须是在 Elasticsearch 的安装目录下进行执行。我们可以通过如下的命令来进行配置:
PUT _snapshot/my_s3_repo { "type": "s3", "settings": { "bucket": "my_s3_bucket_name" } }
这里的 my_s3_bucket_name 是我们在AWS上定义的 S3 bucket。更多关于 S3 的配置可以参阅链接 Repository Settings。
Snapshot 所有的索引
一旦我们的 repository 已经被配置好了,那么我们就可以利用 _snapshot 终点来进行 snapshot。必须注意的是 snapshot 只拷贝在执行该命令时的所有的数据,而在之后的所有的数据将不被备份。snapshot 是按照增量来进行备份的,也就是说它只拷贝从上次执行 snapshot 之后变化的部分。通常来说,每隔30分钟进行一次备份是足够的。
snapshot 命令:
PUT _snapshot/my_repo/my_snapshot_1
这里必须注意的几点:
my_repo 是指的我们在上面定义的 repository 的名字
my_snapshot_1 指的是一个唯一的 snapshot 名字
没有特定的索引名字被指出,那么它指的是所有的 open 索引
如果我们想指定某个或某些特定的索引,那么我们可以使用如下的命令来执行备份(snapshot)
PUT _snapshot/my_repo/my_logs_snapshot_1 { "indices": "logs-*", "ignore_unavailable": true, "include_global_state": true }
这里它表述我们相对所有以 logs- 为开头的索引进行备份。
我们可以通过如下的命令来进行监测正在进行的 snapshot 的进度:
GET _snapshot/my_repo/my_snapshot_2/_status
管理 snapshots
获取所有在 repo 中的 snapshots:
GET _snapshot/my_repo/_all
获取某个特定 snapshot 的信息
GET _snapshot/my_repo/my_snapshot_1
删除一个 snapshot
DELETE _snapshot/my_repo/my_snapshot_1
恢复一个 snapshot
我们可以使用_restore终点来从一个snapshot恢复所有的索引:
POST _snapshot/my_repo/my_snapshot_2/_restore
我们也可以通过如下的方法来恢复某个或某些特定的索引:
POST _snapshot/my_repo/my_snapshot_2/_restore { "indices": "logs-*", "ignore_unavailable": true, "include_global_state": false }
在很多的时候,我们想把 snapshot 中的索引恢复到一个不同名字的索引之中,从而不用覆盖现有的。我们可以通过 rename_pattern 及 rename_replacement 来进行配置:
POST _snapshot/my_repo/my_snapshot_2/_restore { "indices": "logs-*", "ignore_unavailable": true, "include_global_state": false, "rename_pattern": "logs-(.+)", "rename_replacement": "restored-logs-$1" }
在上面,我们把所有的以 logs-* 为开头的索引恢复到以 restored-logs-* 的开头的索引之中来。
Restore 到一个新的 cluster
针对这个情况,我们可以恢复从另外一个 cluster 中备份的 snapshot 到当前的 cluster 中来。我们必须在新的 cluster 中注册这个 repository 才可以进行下面的操作。
从上面我们可以看出来,my_repo 必须对两个 cluster 都是可见的才可以。
动手实践
准备数据:
运行起来我们的 Kibana:
我们分别点击上面的1和2处:
点击上面的 “Add data”。这样我们就可以把我们的 kibana_sample_data_logs 索引
加载到 Elasticsearch 中。
GET _cat/indices/kibana_sample_data_logs
注册 repository
首先我们在我们的电脑上创建一个如下的目录:
/shared_folder/my_repo
我们在 termimal 中打入如下的命令:
cd mkdir -p shared_folder/my_repo/
$ pwd /Users/liuxg/shared_folder bogon:shared_folder liuxg$ ls -al drwxr-xr-x 2 liuxg staff 64 Nov 13 13:23 my_repo
将以下 path.repo 属性添加到我们运行的所有 node 的 elasticsearch.yml 文件中:
path.repo: /Users/liuxg/shared_folder/my_repo
注意,针对你的情况,你需要改动这里的 path 路径。
然后启动我们的 Elasticsearch 及 Kibana。紧接着,我们在 Kibana console 中打入如下的命令:
PUT _snapshot/my_local_repo/snapshot_1 { "indices": "kibana_sample_data_logs", "ignore_unavailable": true, "include_global_state": true }
注意这里的 location 是根据我自己的电脑的路径来设置的。你需要根据自己实际的路径进行修改。在这里 my_local_repo 是我们的 repository 名称。
接下来,我们打入如下的命令来对我们的 kibana_sample_data_logs 索引进行 snapshot:
PUT _snapshot/my_local_repo/snapshot_1 { "indices": "kibana_sample_data_logs", "ignore_unavailable": true, "include_global_state": true }
我们可以通过如下的 _status 终点来查看当前的 snapshot 的进度:
GET _snapshot/my_local_repo/snapshot_1/_status
我们可以通过如下的命令来查看 snapshot:
GET _snapshot/my_local_repo/_all
我们可以在右边看到 snapshot_1 出现在列表之中,说明我们已经成功地创建了这个 snapshot。
我们接下来可以通过如下的命令来删除 kibana_sample_data_logs 索引:
DELETE kibana_sample_data_logs
这样我们彻底地删除了这个索引。那么我们该如何把之前备份的数据恢复回来呢?
在Kibana中打入如下的命令:
POST _snapshot/my_local_repo/snapshot_1/_restore { "indices": "kibana_sample_data_logs", "ignore_unavailable": true, "include_global_state": false }
在执行完上面的命令后,我们可以通过如下的命令来查看恢复后的kibana_sample_data_logs索引:
GET kibana_sample_data_logs/_count
显然我们已经成功地恢复了我们之前备份的数据。
这个时候,如果我们去到我们的 snapshot 文件目录,我们可以看到:
$ pwd /Users/liuxg/shared_folder/my_repo bogon:my_repo liuxg$ ls index-0 meta-TzygGpJ1SOK5yJdsmc1lng.dat index.latest snap-TzygGpJ1SOK5yJdsmc1lng.dat indices
显然在文件目录中,已经有新生产的文件了。
如果你不想通过上面的 API 来进行备份,想通过 Kibana 的界面对 snapshot 进行管理,请阅读我之前的文章 “Elasticsearch:Snapshot 生命周期管理”。