前言

生产环境中运行的组件,只要有数据存储,定时备份、灾难恢复是必修课,mysql数据库的备份方案已经非常成熟,Elasticsearch也同样有成熟的数据备份、恢复方案,我们来了解一下。

概要

本篇介绍Elasticsearch生产集群数据的数据备份、恢复和升级的常规操作。

curl命令

curl是Linux操作的必备工具,Elasticsearch生产环境的搭建,不能保证都能使用kibana访问到,而Elasticsearch Restful API都可以使用curl工具来完成访问。

使用curl还有一个好处:有些操作需要一连串的请求才能完成,我们可以使用shell脚本将这些关联的操作,封装到脚本里,后续使用起来就非常方便。

如果有定时执行的命令,也是使用shell将一系列操作封装好,运用Linux自带的crontab进行触发。

后续的一些操作命令,将会用curl来完成,并且只需要将完整的curl请求拷贝到kibana的dev tools上,kibana能够自动转化成我们之前常见的请求,非常方便。

在Linux下的请求命令:

[esuser@elasticsearch02 ~]$ curl -XGET 'http://elasticsearch02:9200/music/children/_search?pretty' -H 'Content-Type: application/json' -d '
{
  "query": {
    "match_all": {}
  }
}
'

完整的命令拷贝到dev tools里时,自动会变成:

GET /music/children/_search
{

  "query": {

    "match_all": {}

  }

}

这工具真是强大,不过反过来操作不行的,我已经试过了。

curl命令,有Body体的,记得加上-H 'Content-Type: application/json'?pretty参数可以让响应结果格式化输出

数据备份

我们知道Elasticsearch的索引拆分成多个shard进行存储在磁盘里,shard虽然分了primary shard和replica shard,可以保证集群的数据不丢失,数据访问不间断,但如果机房停电导致集群节点全部宕机这种重大事故时,我们就需要提前定期地对数据进行备份,以防万一。

既然是磁盘文件存储,那存储介质的选择就有很多了:本地磁盘,NAS,文件存储服务器(如FastDFS、HDFS等),各种云存储(Amazon S3, 阿里云OSS)等

同样的,Elasticsearch也提供snapshot api命令来完成数据备份操作,可以把集群当前的状态和数据全部存储到一个其他目录上,本地路径或网络路径均可,并且支持增量备份。可以根据数据量来决定备份的执行频率,增量备份的速度还是很快的。

创建备份仓库

我们把仓库地址暂定为本地磁盘的/home/esuser/esbackup目录,

首先,我们需要在elasticsearch.yml配置文件中加上

path.repo: /home/esuser/esbackup

并重启Elasticsearch。

启动成功后,发送创建仓库的请求:

[esuser@elasticsearch02 ~]$ curl -XPUT 'http://elasticsearch02:9200/_snapshot/esbackup?pretty' -H 'Content-Type: application/json' -d '
{
    "type": "fs", 
    "settings": {
        "location": "/home/esuser/esbackup",
        "max_snapshot_bytes_per_sec" : "50mb", 
        "max_restore_bytes_per_sec" : "50mb"
    }
}
'
{"acknowledged":true}
[esuser@elasticsearch02 ~]$

参数解释:

  • type: 仓库的类型名称,请求里都是fs,表示file system。
  • location: 仓库的地址,要与elasticsearch.yml配置文件相同,否则会报错
  • max_snapshot_bytes_per_sec: 指定数据从Elasticsearch到仓库(数据备份)的写入速度上限,默认是20mb/s
  • max_restore_bytes_per_sec: 指定数据从仓库到Elasticsearch(数据恢复)的写入速度上限,默认也是20mb/s

用于限流的两个参数,需要根据实际的网络进行设置,如果备份目录在同一局域网内,可以设置得大一些,便于加快备份和恢复的速度。

也有查询命令可以看仓库的信息:

[esuser@elasticsearch02 ~]$ curl -XGET 'http://elasticsearch02:9200/_snapshot/esbackup?pretty'

{"esbackup":{"type":"fs","settings":{"location":"/home/esuser/esbackup","max_restore_bytes_per_sec":"50mb","max_snapshot_bytes_per_sec":"50mb"}}}

[esuser@elasticsearch02 ~]$

使用hdfs创建仓库

大数据这块跟hadoop生态整合还是非常推荐的方案,数据备份这块可以用hadoop下的hdfs分布式文件存储系统,关于hadoop集群的搭建方法,需要自行完成,本篇末尾有补充说明,可供参考。

对Elasticsearch来说,需要安装repository-hdfs的插件,我们的Elasticsearch版本是6.3.1,对应的插件则使用repository-hdfs-6.3.1.zip,hadoop则使用2.8.1版本的。

插件下载安装命令:

./elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/repository-hdfs/repository-hdfs-6.3.1.zip

如果生产环境的服务器无法连接外网,可以先在其他机器上下载好,上传到生产服务器,解压到本地,再执行安装:

./elasticsearch-plugin install file:///opt/elasticsearch/repository-hdfs-6.3.1

安装完成后记得重启Elasticsearch节点。

查看节点状态:

[esuser@elasticsearch02 ~]$ curl -XGET elasticsearch02:9200/_cat/nodes?v

ip             heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.17.137           38          95   2    0.03    0.03     0.05 mdi       *      node-1

创建hdfs仓库

先查看节点的shard信息

[esuser@elasticsearch02 ~]$ curl -XGET 'http://elasticsearch02:9200/_count?pretty' -H 'Content-Type: application/json' -d '
 {
     "query": {
         "match_all": {}
     }
}'


{
  "count" : 5392,
  "_shards" : {
    "total" : 108,
    "successful" : 108,
    "skipped" : 0,
    "failed" : 0
  }
}

创建一个hdfs的仓库,名称为hdfsbackup

[esuser@elasticsearch02 ~]$ curl -XPUT  'http://elasticsearch02:9200/_snapshot/hdfsbackup?pretty' -H 'Content-Type: application/json' -d '
 {
   "type": "hdfs",
   "settings": {
     "uri": "hdfs://elasticsearch02:9000/",
     "path": "/home/esuser/hdfsbackup",
   "conf.dfs.client.read.shortcircuit": "false",
   "max_snapshot_bytes_per_sec" : "50mb", 
     "max_restore_bytes_per_sec" : "50mb"
   }
 }'

{
  "acknowledged" : true
}

验证仓库

仓库创建好了之后,可以用verify命令验证一下:

[esuser@elasticsearch02 ~]$ curl -XPOST 'http://elasticsearch02:9200/_snapshot/hdfsbackup/_verify?pretty'
{
  "nodes" : {
    "A1s1uus7TpuDSiT4xFLOoQ" : {
      "name" : "node-1"
    }
  }
}

索引备份

仓库创建好并验证完成后,可以执行snapshot api对索引进行备份了,

如果不指定索引名称,表示备份当前所有open状态的索引都备份,还有一个参数wait_for_completion,表示是否需要等待备份完成后才响应结果,默认是false,请求提交后会立即返回,然后备份操作在后台异步执行,如果设置为true,请求就变成同步方式,后台备份完成后,才会有响应。建议使用默认值即可,有时备份的整个过程会持续1-2小时。

示例1:备份所有的索引,备份名称为snapshot_20200122

[esuser@elasticsearch02 ~]$ curl -XPUT 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122?pretty'
{
  "accepted" : true
}

示例2:备份索引music的数据,备份名称为snapshot_20200122_02,并指定wait_for_completion为true

[esuser@elasticsearch02 ~]$ curl -XPUT 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122_02?wait_for_completion=true&pretty' -H 'Content-Type: application/json' -d '
{
  "indices": "music",
  "ignore_unavailable": true,
  "include_global_state": false,
  "partial": true
}'


{
  "snapshot" : {
    "snapshot" : "snapshot_20200122_02",
    "uuid" : "KRXnzc6XSWagCQO92EQx6A",
    "version_id" : 6030199,
    "version" : "6.3.1",
    "indices" : [
      "music"
    ],
    "include_global_state" : false,
    "state" : "SUCCESS",
    "start_time" : "2020-01-22T07:11:06.594Z",
    "start_time_in_millis" : 1579677066594,
    "end_time" : "2020-01-22T07:11:07.313Z",
    "end_time_in_millis" : 1579677067313,
    "duration_in_millis" : 719,
    "failures" : [ ],
    "shards" : {
      "total" : 5,
      "failed" : 0,
      "successful" : 5
    }
  }
}

这条命令中几个参数介绍:

  • indices:索引名称,允许写多个,用","分隔,支持通配符。
  • ignore_unavailable:可选值true/false,如果为true,indices里不存在的index就可以忽略掉,备份操作正常执行,默认是false,如果某个index不存在,备份操作会提示失败。
  • include_global_state:可选值true/false,含义是要不要备份集群的全局state数据。
  • partial:可选值true/false,是否支持备份部分shard的数据。默认值为false,如果索引的部分primary shard不可用,partial为false时备份过程会提示失败。

使用snapshot api对数据的备份是增量进行的,执行snapshotting的时候,Elasticsearch会分析已经存在于仓库中的snapshot对应的index file,在前一次snapshot基础上,仅备份创建的或者发生过修改的index files。这就允许多个snapshot在仓库中可以用一种紧凑的模式来存储,非常节省存储空间,并且snapshotting过程是不会阻塞所有的Elasticsearch读写操作的。

同样的,snapshot作为数据快照,在它之后写入index中的数据,是不会反应到这次snapshot中的,snapshot数据的内容包含index的副本,也可以选择是否保存全局的cluster元数据,元数据里面包含了全局的cluster设置和template。

每次只能执行一次snapshot操作,如果某个shard正在被snapshot备份,那么这个shard此时就不能被移动到其他node上去,这会影响shard rebalance的操作。只有在snapshot结束之后,这个shard才能够被移动到其他的node上去。

查看snapshot备份列表

  1. 查看仓库内所有的备份列表
curl -XGET 'http://elasticsearch02:9200/_snapshot/hdfsbackup/_all?pretty'
  1. 查看单个备份数据
[esuser@elasticsearch02 ~]$ curl -XGET 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122_02?pretty'
{
  "snapshots" : [
    {
      "snapshot" : "snapshot_20200122_02",
      "uuid" : "KRXnzc6XSWagCQO92EQx6A",
      "version_id" : 6030199,
      "version" : "6.3.1",
      "indices" : [
        "music"
      ],
      "include_global_state" : false,
      "state" : "SUCCESS",
      "start_time" : "2020-01-22T07:11:06.594Z",
      "start_time_in_millis" : 1579677066594,
      "end_time" : "2020-01-22T07:11:07.313Z",
      "end_time_in_millis" : 1579677067313,
      "duration_in_millis" : 719,
      "failures" : [ ],
      "shards" : {
        "total" : 5,
        "failed" : 0,
        "successful" : 5
      }
    }
  ]
}

删除snapshot备份

如果需要删除某个snapshot备份快照,一定要使用delete命令,造成别自个跑到服务器目录下做rm操作,因为snapshot是增量备份的,里面有各种依赖关系,极可能损坏backup数据,记住不要上来就自己干文件,让人家标准的命令来执行,命令如下:

[esuser@elasticsearch02 ~]$ curl -XDELETE 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122?pretty'
{
  "acknowledged" : true
}

查看备份进度

备份过程长短视数据量而定,wait_for_completion设置为true虽然可以同步得到结果,但时间太长的话也不现实,我们是希望备份操作后台自己搞,我们时不时的看看进度就行,其实还是调用的snapshot的get操作命令,加上_status参数即可,备份过程中会显示什么时间开始的,有几个shard在备份等等信息:

curl -XGET 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122_02/_status?pretty'

取消备份

正在备份的数据可以执行取消,使用的是delete命令:

curl -XDELETE 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122?pretty'

这个命令有两个作用:

  1. 如果备份正在进行中,那么取消备份操作,并且删除备份了一半的数据。
  2. 如果备份已经完成,直接删除备份数据。

数据恢复

生产环境的备份操作,是定期执行的,执行的频率看实际的数据量,有1天执行1次的,有4小时一次的,简单的操作是使用shell脚本封装备份的命令,然后使用Linux的crontab定时执行。

既然数据有备份,那如果数据出现异常,或者需要使用到备份数据时,恢复操作就能派上用场了。

常规恢复

数据恢复使用restore命令,示例如下:

[esuser@elasticsearch02 ~]$ curl -XPOST 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122_02/_restore?pretty'
{
  "accepted" : true
}

注意一下被恢复的索引,必须全部是close状态的,否则会报错,关闭索引的命令:

[esuser@elasticsearch02 ~]$ curl -XPOST  'http://elasticsearch02:9200/music/_close?pretty'

恢复完成后,索引自动还原成open状态。

同样有些参数可以进行选择:

[esuser@elasticsearch02 ~]$ curl -XPOST 'http://elasticsearch02:9200/_snapshot/hdfsbackup/snapshot_20200122_02/_restore
{
    "indices": "music", 
    "ignore_unavailable": true,
    "include_global_state": true
}

默认会把备份数据里的索引全部还原,我们可以使用indices参数指定需要恢复的索引名称。同样可以使用wait_for_completion参数,ignore_unavailable、partial和include_global_state与备份时效果相同,不赘述。

监控restore的进度

与备份类似,调用的recovery的get操作命令查看恢复的进度:

curl -XGET 'http://elasticsearch02:9200/music/_recovery?pretty'

music为索引名称。

取消restore

与备份类似,delete正在恢复的索引可以取消恢复过程:

curl -XDELETE 'http://elasticsearch02:9200/music'

集群升级

我们现在使用的版本是6.3.1,目前官网最新版本已经是7.5.2了,如果没有重大的变更或严重bug报告的情况下,一般是不需要做升级,毕竟升级有风险,发布要谨慎。

这里就简单说一下通用的步骤,谨慎操作:

  1. 查看官网最新版本的文档,从当前版本到目标版本的升级,有哪些变化,新加入的功能和修复的bug。
  2. 在开发环境或测试环境先执行升级,相应的插件也做一次匹配升级,稳定运行几个项目版本周期后,再考虑生产环境的升级事宜。
  3. 升级前对数据进行全量的备份,万一升级失败,还有挽救的余地。
  4. 申请生产环境升级的时间窗口,逐个node进行升级验证。

补充hadoop集群搭建

Elasticsearch的数据备份,通常建议的实践方案是结合hadoop的hdfs文件存储,这里我们搭建一个hadoop的集群环境用作演示,hadoop相关的基础知识请自行了解,已经掌握的童鞋可以跳过。

版本环境:
hadoop 2.8.1

虚拟机环境

hadoop集群至少需要3个节点。我们选用elasticsearch02、elasticsearch03、elasticsearch04三台机器用于搭建。

  1. 下载解压

官网下载hadoop-2.8.1.tar.gz,解压至/opt/hadoop目录

  1. 设置环境变量

演示环境拥有root权限,就介绍一种最简单的设置方法,修改/etc/profile文件,添加变量后记得source一下该文件。

[root@elasticsearch02 ~]# vi /etc/profile

# 文件末尾添加
export HADOOP_HOME=/opt/hadoop/hadoop-2.8.1
export PATH=${HADOOP_HOME}/bin:$PATH

[root@elasticsearch02 ~]# source /etc/profile
  1. 创建hadoop数据目录,启动hadoop时我们使用esuser账户,就在/home/esuser下创建目录,如 /home/esuser/hadoopdata
  2. 修改hadoop的配置文件,在/opt/hadoop/hadoop-2.8.1/etc/hadoop目录下,基本上是添加配置,涉及的配置文件:
  • core-site.xml
  • hdfs-site.xml
  • yarn-site.xml
  • mapred-site.xml
  • slaves(注:我们选定elasticsearch02为master,其余两个为slave)

示例修改如下:

core-site.xml

<property>
  <name>fs.defaultFS</name>
  <value>hdfs://elasticsearch02:9000</value>
</property>

hdfs-site.xml

<property>
  <name>dfs.namenode.name.dir</name>
  <value>/home/esuser/hadoopdata/namenode</value>
</property>
<property>
  <name>dfs.datanode.data.dir</name>
  <value>/home/esuser/hadoopdata/datanode</value>
</property>

yarn-site.xml

<property>
  <name>yarn.resourcemanager.hostname</name>
  <value>elasticsearch02</value>
</property>

mapred-site.xml

<property>
  <name>mapreduce.framework.name</name>
  <value>yarn</value>
</property>

slaves

elasticsearch03
elasticsearch04
  1. 拷贝设置后的文件到另外两台机器上
scp -r /opt/hadoop/hadoop-2.8.1 esuser@elasticsearch03:/opt/hadoop/hadoop-2.8.1
scp -r /opt/hadoop/hadoop-2.8.1 esuser@elasticsearch04:/opt/hadoop/hadoop-2.8.1

拷贝的文件有点大,需要等一会儿,拷贝完成后,在elasticsearch03、elasticsearch04再设置一次HADOOP_HOME环境变量

  1. 启动集群

格式化namenode,在hadoop master节点(elasticsearch02),HADOOP_HOME/sbin目录下执行hdfs namenode -format

执行启动命令:start-dfs.sh 这个启动过程会建立到elasticsearch03、elasticsearch04的ssh连接,输入esuser的密码即可,也可以提前建立好免密ssh连接。

我们只需要用它的hdfs服务,其他的组件可以不启动。

验证启动是否成功,三台机器分别输入jps,看下面的进程,如无意外理论上应该是这样:
elasticsearch02:NameNode、SecondaryNameNode
elasticsearch03:DataNode
elasticsearch04:DataNode

同时在浏览器上输入hadoop master的控制台地址:http://192.168.17.137:50070/dfshealth.html#tab-overview,应该能看到这两个界面:

es批量保存_hdfs

es批量保存_es批量保存_02

datanodes看到2个结点,表示集群启动成功,如果只能看到一个或一个都没有,可以查看相应的日志:/opt/hadoop/hadoop-2.8.1/logs

Error: JAVA_HOME is not set and could not be found 错误解决办法

这个明明已经设置了JAVA_HOME,并且export命令也能看到,启动时死活就是不行

在/opt/hadoop/hadoop-2.8.1/etc/hadoop/hadoop-env.sh文件加上
export JAVA_HOME="/opt/jdk1.8.0_211"