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

0 - 背景

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

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

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

1 - 備份

1.1 - 安裝hdfs插件

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

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

1.2 - 創(chuàng)建倉庫

在hdfs node上,都加入hdfs-site.xml,禁止權(quán)限檢查,如果要修改這個(gè)配置文件,停止整個(gè)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版本跟這個(gè)es hdfs plugin的版本不兼容,那么考慮在hdfs plugin的文件夾里,將hadoop相關(guān)jar包都替換成我們自己的hadoop版本對(duì)應(yīng)的jar包。即使hadoop已經(jīng)在es所在機(jī)器上也安裝了,但是為了安全考慮,還是應(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 - 驗(yàn)證倉庫

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

POST _snapshot/my_hdfs_repository/_verify

1.4 - 對(duì)索引進(jìn)行snapshotting備份

對(duì)所有open的索引進(jìn)行snapshotting備份

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

對(duì)指定的索引進(jìn)行snapshotting備份

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

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

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

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

1.5 - 查看snapshot備份列表

一旦我們?cè)趥}庫中備份了一些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備份

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

DELETE _snapshot/my_hdfs_repository/snapshot_2

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

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

GET _snapshot/my_hdfs_repository/snapshot_2/_status

1.8 - 取消snapshotting備份過程

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

DELETE _snapshot/my_hdfs_repository/snapshot_2

3 - 還原

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

POST _snapshot/my_hdfs_repository/snapshot_2/_restore

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

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" 
}

這個(gè)restore過程也是在后臺(tái)運(yùn)行的,如果要在前臺(tái)等待它運(yùn)行完,那么可以加上:

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

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

restore過程只能針對(duì)已經(jīng)close掉的index來執(zhí)行,而且這個(gè)index的shard還必須跟snapshot中的indexshard數(shù)量是一致的。restore操作會(huì)自動(dòng)在恢復(fù)好一個(gè)index之后open這個(gè)index,或者如果這些index不存在,那么就會(huì)自動(dòng)創(chuàng)建這些index。如果通過include_global_state存儲(chǔ)了集群的state,還會(huì)同時(shí)恢復(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的進(jìn)度
從一個(gè)倉庫中恢復(fù)數(shù)據(jù),其實(shí)內(nèi)部機(jī)制跟從其他的node上恢復(fù)一個(gè)shard是一樣的。如果要監(jiān)控這個(gè)恢復(fù)的過程,可以用recovery api,比如:

GET restored_index_3/_recovery

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

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

DELETE restored_index_3

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

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

  • snapshop_202008041000
  • snapshop_202008041010
  • snapshop_202008041020

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

POST _snapshot/ES/snapshop_202008041020/_restore

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

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

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

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

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

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

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

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

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