ElasticSearch基于snapshot和hdfs的備份和恢復(fù)

0 - 背景

任何一個存儲數(shù)據(jù)的軟件,都需要定期的備份數(shù)據(jù)。es replica提供了運行時的高可用保障機制,可以容忍少數(shù)節(jié)點的故障和部分?jǐn)?shù)據(jù)的丟失,但是整體上卻不會丟失任何數(shù)據(jù),而且不會影響集群運行。但是replica沒法進行災(zāi)難性的數(shù)據(jù)保護,比如說機房徹底停電,所有機器全部宕機,等等情況。對于這種災(zāi)難性的故障,我們就需要對集群中的數(shù)據(jù)進行備份了,集群中數(shù)據(jù)的完整備份。

要備份集群數(shù)據(jù),就要使用snapshot api。這個api會將集群當(dāng)前的狀態(tài)和數(shù)據(jù)全部存儲到一個外部的共享目錄中去,比如NAS,或者h(yuǎn)dfs。而且備份過程是非常智能的,第一次會備份全量的數(shù)據(jù),但是接下來的snapshot就是備份兩次snapshot之間的增量數(shù)據(jù)了。數(shù)據(jù)是增量進入es集群或者從es中刪除的,那么每次做snapshot備份的時候,也會自動在snapshot備份中增量增加數(shù)據(jù)或者刪除部分?jǐn)?shù)據(jù)。因此這就意味著每次增量備份的速度都是非??斓摹?/p>

如果要使用這個功能,我們需要有一個預(yù)先準(zhǔn)備好的獨立于es之外的共享目錄,用來保存我們的snapshot備份數(shù)據(jù)。es支持多種不同的目錄類型:shared filesystem,比如NAS;Amazon S3;hdfs;Azure Cloud。不過對于國內(nèi)的情況而言,其實NAS應(yīng)該很少用,一般來說,就用hdfs會比較多一些,跟hadoop這種離線大數(shù)據(jù)技術(shù)棧整合起來使用。

1 - 備份

1.1 - 安裝hdfs插件

首先先要在es插件目錄安裝repository-hdfs的插件,必須在每個節(jié)點上都安裝,然后重啟整個集群。

./bin/elasticsearch-plugin install file:/opt/soft/repository-hdfs-6.8.0.zip

1.2 - 創(chuàng)建倉庫

在hdfs node上,都加入hdfs-site.xml,禁止權(quán)限檢查,如果要修改這個配置文件,停止整個hdfs集群,然后在node上,都修改hdfs-site.xml,加入下面的配置,禁止權(quán)限的檢查:

<property>
  <name>dfs.permissions</name>
  <value>false</value>
</property>

hdfs snapshot/restore plugin是跟最新的hadoop 2.x整合起來使用的,目前是hadoop 2.7.1。所以如果我們使用的hadoop版本跟這個es hdfs plugin的版本不兼容,那么考慮在hdfs plugin的文件夾里,將hadoop相關(guān)jar包都替換成我們自己的hadoop版本對應(yīng)的jar包。即使hadoop已經(jīng)在es所在機器上也安裝了,但是為了安全考慮,還是應(yīng)該將hadoop jar包放在hdfs plugin的目錄中。

安裝好了hdfs plugin之后,就可以創(chuàng)建hdfs倉庫了,用如下的命令即可:

PUT _snapshot/my_hdfs_repository
{
  "type": "hdfs",
  "settings": {
    "uri": "hdfs://hdfs01:9000",
    "path": "my_hdfs_repository",
    "max_snapshot_bytes_per_sec" : "50mb",
    "max_restore_bytes_per_sec" : "50mb"
  }
}

1.3 - 驗證倉庫

如果一個倉庫被創(chuàng)建好之后,我們可以立即去驗證一下這個倉庫是否可以在所有節(jié)點上正常使用。verify參數(shù)都可以用來做這個事情,比如下面的命令。這個命令會返回一個node列表,證明那些node都驗證過了這個倉庫是ok的,可以使用的:

POST _snapshot/my_hdfs_repository/_verify

1.4 - 對索引進行snapshotting備份

對所有open的索引進行snapshotting備份

一個倉庫可以包含多分snapshot,每個snapshot是一部分索引的備份數(shù)據(jù),創(chuàng)建一份snapshot備份時,我們要指定要備份的索引。比如下面這行命令:PUT _snapshot/my_hdfs_repository/snapshot_1,這行命令就會將所有open的索引都放入一個叫做snapshot_1的備份,并且放入my_hdfs_repository倉庫中。這個命令會立即返回,然后備份操作會被后臺繼續(xù)進行。如果我們不希望備份操作以后臺方式運行,而是希望在前臺發(fā)送請求時等待備份操作執(zhí)行完成,那么可以加一個參數(shù)即可,比如下面這樣:PUT _snapshot/my_hdfs_repository/snapshot_1?wait_for_completion=true。

對指定的索引進行snapshotting備份

默認(rèn)的備份是會備份所有的索引,但是有的時候,可能我們不希望備份所有的索引,有些可能是不重要的數(shù)據(jù),而且量很大,沒有必要占用我們的hdfs磁盤資源,那么可以指定備份少數(shù)重要的數(shù)據(jù)即可。此時可以使用下面的命令去備份指定的索引:

PUT _snapshot/my_hdfs_repository/snapshot_1
{
    "indices": "index_1,index_2",
    "ignore_unavailable": true,
    "include_global_state": false,
    "partial": true
}

ignore_unavailable如果設(shè)置為true的話,那么那些不存在的index就會被忽略掉,不會進行備份過程中。默認(rèn)情況下,這個參數(shù)是不設(shè)置的,那么此時如果某個index丟失了,會導(dǎo)致備份過程失敗。設(shè)置include_global_state為false,可以阻止cluster的全局state也作為snapshot的一部分被備份。默認(rèn)情況下,如果某個索引的部分primary shard不可用,那么會導(dǎo)致備份過程失敗,那么此時可以將partial設(shè)置為true

而且snapshotting的過程是增量進行的,每次執(zhí)行snapshotting的時候,es會分析已經(jīng)存在于倉庫中的snapshot對應(yīng)的index file,然后僅僅備份那些自從上次snapshot之后新創(chuàng)建的或者有過修改的index files。這就允許多個snapshot在倉庫中可以用一種緊湊的模式來存儲。而且snapshotting過程是不會阻塞所有的es讀寫操作的,然而,在snapshotting開始之后,寫入index中的數(shù)據(jù),是不會反應(yīng)到這次snapshot中的。每次snapshot除了創(chuàng)建一份index的副本之外,還可以保存全局的cluster元數(shù)據(jù),里面包含了全局的cluster settingstemplate。

每次只能執(zhí)行一次snapshot操作,如果某個shard正在被snapshot備份,那么這個shard此時就不能被移動到其他node上去,這會影響shard rebalance的操作。只有在snapshot結(jié)束之后,這個shard才能夠被移動到其他的node上去。

1.5 - 查看snapshot備份列表

一旦我們在倉庫中備份了一些snapshot之后,就可以查看這些snapshot相關(guān)的詳細(xì)信息了,使用這行命令就可以查看指定的snapshot的詳細(xì)信息:GET _snapshot/my_hdfs_repository/snapshot_2,結(jié)果大致如下所示。當(dāng)然也可以查看所有的snapshot列表,GET _snapshot/my_hdfs_repository/_all

GET _snapshot/my_hdfs_repository/snapshot_2?pretty
{
  "snapshots" : [
    {
      "snapshot" : "snapshot_0",
      "uuid" : "ulzZ-zosRAWHsBVmVJ5SJA",
      "version_id" : 6080099,
      "version" : "6.8.0",
      "indices" : [
        "mysia"
      ],
      "include_global_state" : false,
      "state" : "SUCCESS",
      "start_time" : "2020-06-09T01:59:26.923Z",
      "start_time_in_millis" : 1591667966923,
      "end_time" : "2020-06-09T01:59:28.289Z",
      "end_time_in_millis" : 1591667968289,
      "duration_in_millis" : 1366,
      "failures" : [ ],
      "shards" : {
        "total" : 5,
        "failed" : 0,
        "successful" : 5
      }
    }
  ]
}

1.6 - 刪除snapshot備份

如果要刪除過于陳舊的snapshot備份快照,那么使用下面這行命令即可:DELETE _snapshot/my_hdfs_repository/snapshot_2。記住,一定要用api去刪除snapshot,不要自己手動跑到hdfs里刪除這個數(shù)據(jù)。因為snapshot是增量的,有可能很多snapshot依賴于底層的某一個公共的舊的snapshot segment。但是delete api是理解數(shù)據(jù)如何增量存儲和互相依賴的,所以可以正確的刪除那些不用的數(shù)據(jù)。如果我們自己手工進行hdfs文件刪除,可能導(dǎo)致我們的backup數(shù)據(jù)破損掉,就無法使用了。

DELETE _snapshot/my_hdfs_repository/snapshot_2

1.7 - 監(jiān)控snapshotting的進度

使用wait_for_completion可以在前臺等待備份完成,但是實際上也沒什么必要,因為可能要備份的數(shù)據(jù)量特別大,難道還等待1個小時??看著是不太現(xiàn)實的,所以一般還是在后臺運行備份過程,然后使用另外一個監(jiān)控api來查看備份的進度,首先可以獲取一個snapshot IDGET _snapshot/my_hdfs_repository/snapshot_3。如果這個snapshot還在備份過程中,此時我們就可以看到一些信息,比如什么時候開始備份的,已經(jīng)運行了多長時間,等等。然而,這個api用了跟snapshot一樣的線程池去執(zhí)行,如果我們在備份非常大的shard,進度的更新可能會非常之慢。一個更好的選擇是用_status API,GET _snapshot/my_hdfs_repository/snapshot_3/_status,這個api立即返回最詳細(xì)的數(shù)據(jù)。這里我們可以看到總共有幾個shard在備份,已經(jīng)完成了幾個,還剩下幾個,包括每個索引的shard的備份進度:

GET _snapshot/my_hdfs_repository/snapshot_2/_status

1.8 - 取消snapshotting備份過程

如果我們想要取消一個正在執(zhí)行的snapshotting備份過程,比如我們發(fā)現(xiàn)備份時間過于長,希望先取消然后在晚上再運行,或者是因為不小心誤操作發(fā)起了一次備份操作,這個時候就可以運行下面這條命令:DELETE _snapshot/my_hdfs_repository/snapshot_2。也就是立即刪除這個snapshot,這個命令會去取消snapshot的過程,同時將備份了一半的倉庫中的數(shù)據(jù)給刪除掉。

DELETE _snapshot/my_hdfs_repository/snapshot_2

3 - 還原

一般來說,備份工作是在一個shell腳本里,用crontab做一個定時去做增量備份。那么在es集群故障,導(dǎo)致數(shù)據(jù)丟失的時候,就可以用_restore api進行數(shù)據(jù)恢復(fù)了。比如下面這行命令:

POST _snapshot/my_hdfs_repository/snapshot_2/_restore

文件中所有索引都全恢復(fù)。在某些場景下,我們想恢復(fù)一些數(shù)據(jù)但是不要覆蓋現(xiàn)有數(shù)據(jù),用下面的命令即可恢復(fù)數(shù)據(jù),并且進行重命名操作:

POST /_snapshot/my_hdfs_repository/snapshot_2/_restore
{
    "indices": "index_1", 
    "ignore_unavailable": true,
    "include_global_state": true,
    "rename_pattern": "index_(.+)", 
    "rename_replacement": "restored_index_$1" 
}

這個restore過程也是在后臺運行的,如果要在前臺等待它運行完,那么可以加上:

POST _snapshot/my_hdfs_repository/snapshot_2/_restore?wait_for_completion=true

等待它備份完成了以后,才會去執(zhí)行下一條命令。

restore過程只能針對已經(jīng)close掉的index來執(zhí)行,而且這個index的shard還必須跟snapshot中的indexshard數(shù)量是一致的。restore操作會自動在恢復(fù)好一個index之后open這個index,或者如果這些index不存在,那么就會自動創(chuàng)建這些index。如果通過include_global_state存儲了集群的state,還會同時恢復(fù)一些template。

此外,還可以在恢復(fù)的過程中,修改index的一些設(shè)置,比如下面的命令:

POST /_snapshot/my_hdfs_repository/snapshot_2/_restore
{
  "indices": "index_1",
  "index_settings": {
    "index.number_of_replicas": 0
  },
  "ignore_index_settings": [
    "index.refresh_interval"
  ]
}

監(jiān)控restore的進度
從一個倉庫中恢復(fù)數(shù)據(jù),其實內(nèi)部機制跟從其他的node上恢復(fù)一個shard是一樣的。如果要監(jiān)控這個恢復(fù)的過程,可以用recovery api,比如:

GET restored_index_3/_recovery

如果要看所有索引的恢復(fù)進度:GET /_recovery/??梢钥吹交謴?fù)進度的大致的百分比。

取消恢復(fù)過程
如果要取消一個恢復(fù)過程,那么需要刪除已經(jīng)被恢復(fù)到es中的數(shù)據(jù)。因為一個恢復(fù)過程就只是一個shard恢復(fù),發(fā)送一個delete操作刪除那個索引即可,如果那個索引正在被恢復(fù),那么這個delete命令就會停止恢復(fù)過程,然后刪除已經(jīng)恢復(fù)的所有數(shù)據(jù)。

DELETE restored_index_3

增量還原
基于snapshot的備份,再做完第一次全量后,其實后續(xù)的備份都是基于上一次備份的增量備份。而Elasticsearch在做還原時,不像MySQLSQL Server那樣,需要先還原全量,在恢復(fù)增量。

假設(shè),有3個Elasticsearch的備份:

  • snapshop_202008041000
  • snapshop_202008041010
  • snapshop_202008041020

如果要還原到最新的備份,也就是snapshop_202008041020這個備份,只需要:

POST _snapshot/ES/snapshop_202008041020/_restore

還原最新備份的同時,Elasticsearch會根據(jù)hdfs倉庫里面?zhèn)浞莸年P(guān)聯(lián)關(guān)系,將之前的備份也一起恢復(fù)。

如果不巧的是,不確定還原到哪個備份,那么就需要依次還原:

還原全量備份:
POST _snapshot/ES/snapshop_202008041000/_restore

此時假設(shè)數(shù)據(jù)還不對,需要還原下一個增量,需要先關(guān)閉索引,再還原增量
POST test_shapshot/_close
POST _snapshot/ES/snapshop_202008041010/_restore

如果數(shù)據(jù)仍然不對,后續(xù)的增量還原,重復(fù)上面的步驟

奇怪的是,官網(wǎng)上的snapshot部分,沒有寫增量還原部分。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容