Elasticsearch的灾备和恢复

时间:2023-01-27 20:14:30

   Es每个节点上只会存储部分的数据,而使用replicas机制已经对数据进行冗余备份,但是对生产的Es进行全量(第一次为全量)和增量数据灾备是非常有必要的。一般会选择将数据灾备到共享文件系统中。但是最终决定使用每日(每周,取决于数据的重要性)定时任务将共享文件的灾备数据打tar包并同步到阿里云的OSS的特定bucket中,即灾备的灾备。虽然定时的快照为增量数据,但是只有es清除那些是增量数据哪些是第一次的基础数据,所以每天需要将全量数据打包并同步到OSS,若OSS只存储5天的全量数据,则在每天同步完之后需要清除5天前的全量数据包。


若发生异常需要恢复数据的时候,首先从共享文件系统直接进行快照恢复,共享文件系统不可用则可以直接从OSS中拉取数据,解压并替换共享目录下的数据,再执行快照恢复命令。


1、灾备

基于Es的snapshot API可以对集群灾备,但是需要先创建仓库,并且在仓库中创建快照(第一次为全量数据,后续为增量数据),而在快照区中分索引。以下是仓库可选择的类型,默认会选择共享文件系统(并且一般会使用sshfs,并且会遇到坑):


       1、共享文件系统,比如 NAS


       2、Amazon S3


       3、HDFS (Hadoop 分布式文件系统)


       4、Azure Cloud


   1、sshfs共享文件系统创建

       安装sshfs:

           yum install sshfs

       在每个节点下配置共享文件目录:

          sudo sshfs -o allow_other -o nonempty root@192.168.10.11:/data/sshfs-repository/ /data/elasticsearch-repository -p 61822(说明:-o allow_other所有用户都可以读写,root用户使用ssh将本地的文件目录/data/elasticsearch-repository共享到远程IP(或域名)为192.168.10.11上的/data/sshfs-repository/目录,若ssh段端口不为22需要使用-p 61822指定,而由于可能存在已经运行过命令,已经挂在过则目录下可能存在文件则可以使用-o nonempty告诉其可以忽略目录下的文件进行删除或修改),如下:

Elasticsearch的灾备和恢复

 若挂在错了,或者需要删除已经挂在的点,可以使用(不要自行删除文件或目录的方式):

           fusermount -uz /data/elasticsearch-repository(后面的路径为本地路径)

       测试,可以在每个节点服务器上运行一下命令检测用户是否对本地的共享文件目录拥有写权限:

           sudo -u elasticsearch touch /data/elasticsearch-repository/test

   2、es配置

   将集群中每个节点下的elasticsearch.yml中添加仓库路径的白名单列表:


           path.repo: /mnt 或 path.repo: [“/path1” , “path2” ]


   3、仓库创建

       需要根据自己的网络设置快照或恢复的限流参数,只要不能影响正常的数据索引和查询聚合请求。


// 使用GET请求用于创建,POST请求若存在则为修改

POST _snapshot/my_backup/ {

   "type": "fs", // 仓库类型为共享文件系统

   "settings": {

       "location": "/mnt",  // 仓库路径,需要与sshfs的远程目录一致,并在需要在es集群的白名单中存在

       "max_snapshot_bytes_per_sec" : "50mb",

       // 当快照数据进入仓库时,这个参数控制这个过程的限流情况。默认是每秒 20mb 。

       "max_restore_bytes_per_sec" : "50mb"

       // 当从仓库恢复数据时,这个参数控制什么时候恢复过程会被限流以保障你的网络不会被占满。默认是每秒 `20mb`。

   }

}

   4、快照相关操作

       1、快照的创建

           创建快照,默认为异步执行,添加参数wait_for_completion则为同步等待,如下:


PUT _snapshot/my_backup/snapshot_1?wait_for_completinotallow=true


       2、索引配置

   由于es集群环境中一般除了业务数据索引外还会有kibana或监控的索引,所以一般会指定需要快照的索引,如下:


PUT _snapshot/my_backup/snapshot_2{

   "indices": "index_1,index_2"

}

       3、获取快照相关信息

           获取某仓库下的一个或索引的快照信息,如下:


GET _snapshot/my_backup/snapshot_2


           或


GET _snapshot/my_backup/_all


       4、监控快照进度

  如果快照距离上一次的数据增量比较大或第一次执行快照,则快照执行的时间可能会比较长,可以使用以下api对其执行状态进行查看(由于使用_status查看的线程和执行快照的线程属于同一类线程池,所以速度回比较慢):


GET _snapshot/my_backup/snapshot_3


           或


GET _snapshot/my_backup/snapshot_3/_status


        5、快照取消或删除

 因为快照是增量的,有可能很多快照依赖于过去的段,索引不能使用人工等方式进行删除操作,而需要使用Es 的delete API。由于快照的过程会比较长,若在执行时需要取消,可以使用与删除一样的API,只是若在还在执行快照的过程中接收到取消操作,则会先中断快照进行,再将已经执行的数据进行删除,命令如下:


DELETE _snapshot/my_backup/snapshot_2


2、恢复

   1、使用快照恢复数据

 由于回复工程默认为异步恢复,可以使用wait_for_completinotallow=true同步获取结果,并且可以使用indices参数指定需要恢复的索引的名称,并且可以使用rename_pattern参数查找所提供的模式能匹配上的正在恢复的索引(没怎么理解),使用rename_replacement参数重命名回复后的索引名称,如下:


POST /_snapshot/my_backup/snapshot_1/_restore?wait_for_completinotallow=true

{

"indices": "index_1",    

"rename_pattern": "index_(.+)",  

"rename_replacement": "restored_index_$1"

}

   2、恢复过程监控

   从仓库恢复数据借鉴了 Elasticsearch 里已有的现行恢复机制。 在内部实现上,从仓库恢复分片和从另一个节点恢复是等价的,使用了Es的recover API,如下:


GET restored_index_3/_recovery


   3、取消恢复

       若在执行过程中需要撤销恢复操作,可以执行删除操作即可,若接收到删除命令首先会停止恢复操作,再将已恢复是数据进行删除,命令如下:


DELETE /restored_index_3


3、ES snapshot java API

若想定时为es集群索引创建快照,则可以使用java定时任务创建,如下:

   private static final String BASE_SNAPSHOT = "snapshot_geleevr_";

/**

 * 每天执行Es集群快照

 *

 * @throws Exception

 */

// @Scheduled(crnotallow="0 0 1 * * ?")

// @Scheduled(fixedRate=30000000)

   public void execute() throws Exception {

    TransportClient client = ESClient.me();

    CreateSnapshotRequestBuilder builder = CreateSnapshotAction.INSTANCE.newRequestBuilder(client);

   

    String snapshotName = BASE_SNAPSHOT + UTCDateUtil.userFormat(new Date());

    long start = System.currentTimeMillis();

    // 快照执行的时间可能比较长,而且不可控(只能定时通过status api查询),所以异步获取状态

    builder.setIndices(ESConfig.COMPANY, ESConfig.ANALYZE)

      .setRepository(ESConfig.ES_REPOSITORY)

      .setSnapshot(snapshotName)

      .execute(new ActionListener<CreateSnapshotResponse>() {

   

    @Override

    public void onResponse(CreateSnapshotResponse response) {

     long end = System.currentTimeMillis();

     long seconds = (long) ((end - start)/1000);

     logger.info("task of snapshot {} is sync sussess , total time is {} seconds !", snapshotName, seconds);

    }

   

    @Override

    public void onFailure(Exception e) {

     long end = System.currentTimeMillis();

     long seconds = (long) ((end - start)/1000);

     logger.error("task of snapshot {} is failure , total time is {} seconds !", snapshotName, seconds);

     

    }

   });

   

   }




4、遇到的问题

   1、doesn't match any of the locations specified by path.repo because this setting is empty

 在为es集群环境做灾备和恢复时候,首先需要创建创建一个仓库,并往仓库中存放快照(每个快照中会区分不同的索引)。但是在创建仓库的时候,要求仓库的地址必须在每个集群环境中的elasticsearch.yml中进行配置(相当于一个白名单列表):


   单个:path.repo: /mnt


   多个:path.repo: [“/data” , “/mnt”]



   2、在使用sshfs创建共享文件系统的时候,报错read: Connection reset by peer

   Es在灾备的时候可以将数据存放到共享文件系统(一般选择sshfs),或hdfs等。但是在执行如sudo sshfs -o allow_other root@192.168.10.11:/data/elasticsearch-repository /mnt的时候,报错read:Connect reset by peer,刚开始以为是es的问题,最后发现就是ssh的问题。由于我使用的是阿里云服务器,并且使用秘钥进行连接,我还以为是它的问题。最后:


       ssh 192.168.10.11


       ssh: connect to host 192.168.10.11 port 22: Connection refused


想起来我修改过ssh的端口,则需要将命令添加端口就好了,如下:

        sudo sshfs -o allow_other root@192.168.10.11:/data/elasticsearch-repository /mnt -p 61822