Elasticsearchのスナップショットは増分で管理されているけど、最も古いスナップショットを削除してもリストアできる

自称OSクラッシュおじさんがElasticsearchを破壊した時に備えてスナップショットの仕様を確認しました。
2021.08.10

Elasticsearchのスナップショットは増分で管理されているらしい

こんにちは、のんピ です。もといOSクラッシュおじさんです。

今まで以下ブログで紹介してる通り、Amazon Linux 2とWindows Serverのシステム領域を削除して、OSを破壊してきました。

そして、つい先日Amazon Elasticsearch Serviceの手動スナップショットをLambdaで管理するブログを書きました。

このブログを書いているとき、ふと「Elasticsearchのスナップショットの仕様を知らないと、安心してElasticsearchを破壊できない」と思いました。

そんな思いを払拭するために、Elasticsearchのスナップショットについて調べると、以下のように「スナップショットは増分で作成され、最後に成功したスナップショット以降に変更されたデータのみを保存する」との記載がありました。

Elasticsearch snapshots are incremental, meaning that they only store data that has changed since the last successful snapshot. The difference in disk usage between frequent and infrequent snapshots is often minimal.

Take and restore snapshots - About snapshots

一般的な増分バックアップは、以下で紹介されているようにフルバックアップが削除されると増分バックアップは使い物になりません

(抜粋: [AWS Black Belt Online Seminar]Amazon Elastic Block Store - EBS Snapshot の世代管理の仕組み)

そこで、Elasticsearchのフルバックアップ = 最も古いスナップショットを削除しても、正しくリストアができるのか気になったので、検証してみます。

いきなりまとめ

  • Elasticsearchのスナップショットは増分で管理されるけど、最も古いスナップショットを削除しても正常にリストアできる

ドキュメントを確認してみる

もう少しドキュメントを確認してみます。

Open Distro for Elasticsearchの以下公式ドキュメントを確認すると、「スナップショットを削除する場合は、ストレージの場所から直接削除するのではなく、必ずElasticsearch APIを使ってください」という記載がありました。

If you need to delete a snapshot, be sure to use the Elasticsearch API rather than navigating to the storage location and purging files. Incremental snapshots from a cluster often share a lot of the same data; when you use the API, Elasticsearch only removes data that no other snapshot is using.

Take and restore snapshots - About snapshots

わざわざAPI経由で削除するということは、単純にスナップショットのデータを削除するだけではなく、裏側で様々な処理が発生していそうですね。

また、ELK Stackの管理ツールである、ELKmanのブログを確認すると以下のような記載がありました。

Deletes are run completely by the master node, and works by first reading the repository to build a list of indices, shards, and segments in the to-be-deleted snapshot. Then the master re-reads all the other snapshots' metadata and importantly, the indexes and segments they contain. It compares the list from the to-be-deleted-snapshot to the used-by-other-snaphots list.

The ones not referenced by any remaining snapshot are marked for deletion, basically deleting segments no longer needed while keeping all those that are. It also deletes any indexes in the repo that are not referenced by remaining snapshots. This elegant solution is very flexible and robust.

How Elasticsearch Snapshots Work - Snapshot Deletes

機械翻訳結果は以下の通りです。

削除は完全にマスターノードによって実行されます。まず、リポジトリを読み込んで、削除するスナップショットのインデックス、シャード、セグメントのリストを作成します。次に、マスターは他のすべてのスナップショットのメタデータを再読み込みし、重要なのは、それらに含まれるインデックスとセグメントを再読み込みします。削除予定のスナップショットのリストと、used-by-other-snaphotsのリストを比較します。

残っているスナップショットから参照されていないものは削除マークが付けられ、基本的に必要のないセグメントは削除されますが、必要なものはすべて残されます。また、残りのスナップショットから参照されていないレポ内のインデックスも削除されます。このエレガントなソリューションは、非常に柔軟で堅牢です。

どうやらスナップショットを削除する際に、他のスナップショットのメタデータを読み込んで、他のスナップショットから参照されているデータは残すようです。

仕組みとしては、EBSスナップショットの世代管理と同様に、最も古いスナップショットを削除してしまっても大丈夫そうですね。

(抜粋: [AWS Black Belt Online Seminar]Amazon Elastic Block Store - EBS Snapshot の世代管理の仕組み)

最も古いスナップショットを削除しても正常にリストアできるか確認してみる

リストア前の準備

それでは、実際に最も古いスナップショットを削除しても正しくリストアができるか確認をしてみます。

まず、リストア前のデータ件数を確認します。Discoverより、2021/8/10 12:00 - 2021/8/10/ 17:00のCloudTrailのデータ件数は、2,462件であることが分かります。

スナップショットは、UTCの2021/8/10 8:39に作成されたものと、2021/8/10 8:59に作成された2つを用意しました。

> GET _snapshot/test-delete-snapshot/*

{
  "snapshots" : [ {
    "snapshot" : "test-delete-snapshot-2021-08-10t08-39-16",
    "uuid" : "Ei3T-zsbTbCy_q0HRww-Qw",
    "version_id" : 7100299,
    "version" : "7.10.2",
    "indices" : [ ".kibana_1", "log-aws-workspaces-000001", ".opendistro-ism-managed-index-history-2021.08.09-1", "log-aws-elb-000001", "log-aws-msk-000001", "log-aws-cloudtrail-2021-08", "log-aws-r53resolver-000001", ".kibana_82490336_aesadmin_1", "log-aws-cloudtrail-000001", "log-aws-waf-000001", "log-aws-fsx-win-000001", "log-aws-s3accesslog-000001", "log-win-event-000001", "log-aws-securityhub-000001", "log-aws-vpcflowlogs-000001", ".opendistro-ism-config", "log-linux-secure-000001", "log-aws-guardduty-000001", ".opendistro_security", "log-aws-cloudfront-000001", ".opendistro-job-scheduler-lock", "log-linux-os-000001", "log-aws-directory-service-000001" ],
    "data_streams" : [ ],
    "include_global_state" : true,
    "state" : "SUCCESS",
    "start_time" : "2021-08-10T08:39:17.143Z",
    "start_time_in_millis" : 1628584757143,
    "end_time" : "2021-08-10T08:39:33.213Z",
    "end_time_in_millis" : 1628584773213,
    "duration_in_millis" : 16070,
    "failures" : [ ],
    "shards" : {
      "total" : 97,
      "failed" : 0,
      "successful" : 97
    }
  }, {
    "snapshot" : "test-delete-snapshot-2021-08-10t08-59-42",
    "uuid" : "OPcjmyCxRaW-bpbXAHqfgg",
    "version_id" : 7100299,
    "version" : "7.10.2",
    "indices" : [ ".kibana_1", "log-aws-workspaces-000001", ".opendistro-ism-managed-index-history-2021.08.09-1", "log-aws-elb-000001", "log-aws-msk-000001", "log-aws-cloudtrail-2021-08", "log-aws-r53resolver-000001", ".kibana_82490336_aesadmin_1", "log-aws-cloudtrail-000001", "log-aws-fsx-win-000001", "log-aws-waf-000001", "log-win-event-000001", "log-aws-s3accesslog-000001", "log-aws-securityhub-000001", "log-aws-vpcflowlogs-000001", ".opendistro-ism-config", "log-linux-secure-000001", "log-aws-guardduty-000001", ".opendistro_security", "log-aws-cloudfront-000001", ".opendistro-job-scheduler-lock", "log-linux-os-000001", "log-aws-directory-service-000001" ],
    "data_streams" : [ ],
    "include_global_state" : true,
    "state" : "SUCCESS",
    "start_time" : "2021-08-10T08:59:42.111Z",
    "start_time_in_millis" : 1628585982111,
    "end_time" : "2021-08-10T08:59:51.918Z",
    "end_time_in_millis" : 1628585991918,
    "duration_in_millis" : 9807,
    "failures" : [ ],
    "shards" : {
      "total" : 97,
      "failed" : 0,
      "successful" : 97
    }
  } ]
}

これで一つ目のスナップショット(test-delete-snapshot-2021-08-10t08-39-16)を削除します。

> DELETE _snapshot/test-delete-snapshot/test-delete-snapshot-2021-08-10t08-39-16

{
  "acknowledged" : true
}

スナップショットの一覧を再度表示すると、確かに削除されていることが確認できます。

GET _snapshot/test-delete-snapshot/*

{
  "snapshots" : [ {
    "snapshot" : "test-delete-snapshot-2021-08-10t08-59-42",
    "uuid" : "OPcjmyCxRaW-bpbXAHqfgg",
    "version_id" : 7100299,
    "version" : "7.10.2",
    "indices" : [ ".kibana_1", "log-aws-workspaces-000001", ".opendistro-ism-managed-index-history-2021.08.09-1", "log-aws-elb-000001", "log-aws-msk-000001", "log-aws-cloudtrail-2021-08", "log-aws-r53resolver-000001", ".kibana_82490336_aesadmin_1", "log-aws-cloudtrail-000001", "log-aws-fsx-win-000001", "log-aws-waf-000001", "log-win-event-000001", "log-aws-s3accesslog-000001", "log-aws-securityhub-000001", "log-aws-vpcflowlogs-000001", ".opendistro-ism-config", "log-linux-secure-000001", "log-aws-guardduty-000001", ".opendistro_security", "log-aws-cloudfront-000001", ".opendistro-job-scheduler-lock", "log-linux-os-000001", "log-aws-directory-service-000001" ],
    "data_streams" : [ ],
    "include_global_state" : true,
    "state" : "SUCCESS",
    "start_time" : "2021-08-10T08:59:42.111Z",
    "start_time_in_millis" : 1628585982111,
    "end_time" : "2021-08-10T08:59:51.918Z",
    "end_time_in_millis" : 1628585991918,
    "duration_in_millis" : 9807,
    "failures" : [ ],
    "shards" : {
      "total" : 97,
      "failed" : 0,
      "successful" : 97
    }
  } ]
}

最後に、リストアする前準備として、CloudTrailのインデックスをクローズします。

> POST log-aws-cloudtrail-2021-08/_close

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "indices" : {
    "log-aws-cloudtrail-2021-08" : {
      "closed" : true
    }
  }
}

CloudTrailのインデックスをクローズした後、Discoverを確認すると「検索条件に一致する結果がありません」とのメッセージが出力されました。

リストアと確認

それでは、以下コマンドでスナップショットからCloudTrailのインデックスをリストアします。

> POST _snapshot/test-delete-snapshot/test-delete-snapshot-2021-08-10t08-59-42/_restore
{
  "indices": "log-aws-cloudtrail-2021-08"
}

{
  "accepted" : true
}

リストア後にDiscoverを確認すると、CloudTrailのデータ件数は、2,696件と正しくインデックスがリストアできていることが分かります。

古いスナップショットを削除しても正常にリストアできる

Elasticsearchのスナップショットの仕様が気になったので検証してみました。

これで安心してElasticsearchを壊せそうです。

以上、東京オフィスの のんピ(@non____97)でした!