ようへいの日々精進XP

よかろうもん

触って身に付く elasticsearch 1.0.0 の Snapshot と Restore 操作メモとスナップショットの仕組みの考察

はじめに

  • elasticsearch 1.0.0 が正式にリリースされたので改めて Snapshot と Restore 機能を試してみる
  • スナップショットの仕組みについて少しだけ深堀りしてみる

操作

EC2 インスタンス上に構築した elasticsearch 1.0.0 リリース版を利用して操作する。また、データ自体はライブドアが提供しているこちらのレストランデータを利用する。

f:id:inokara:20140215094036p:plain

上図の restaurant インデックスを題材に SnapshotRestore 機能を試してみる。ちなみにリクエスト内の ?pretty はお好みで。

リポジトリの一覧

curl -XGET "localhost:9200/_snapshot/?pretty"

以下のように表示される。

{
  "my_s3_repository" : {
    "type" : "s3",
    "settings" : {
      "region" : "ap-northeast-1",
      "bucket" : "elasticsearch-snapshot"
    }
  },
  "my_local_backup" : {
    "type" : "fs",
    "settings" : {
      "compress" : "true",
      "location" : "/home/ubuntu/backup"
    }
  }
}

リポジトリの作成

curl -XPUT 'http://localhost:9200/_snapshot/my_local_backup' -d '{
    "type": "fs",
    "settings": {
        "location": "/home/ubuntu/backup",
        "compress": true
    }
}'

レスポンスは {"acknowledged":true} だけ。シンプル。

リポジトリの削除

curl -XDELETE "localhost:9200/_snapshot/my_local_backup?pretty"

同じくレスポンスは {"acknowledged":true} だけ。シンプル。

スナップショットの取得

snapshot_1 というスナップショット名にスナップショットを取得する。尚、インデックスを指定する場合にはリクエストボディに indices を付ける。

curl -XPUT "localhost:9200/_snapshot/my_local_backup/snapshot_1?pretty&wait_for_completion=true" -d '{
    "indices": "restaurant",
    "ignore_unavailable": "true",
    "include_global_state": false
}'

以下のようにレスポンスが表示される。wait_for_completion=true がある場合にはスナップショットが取得し終わるのを待つ。デフォルトは false になっている。

{
  "snapshot" : {
    "snapshot" : "snapshot_1",
    "indices" : [ "restaurant" ],
    "state" : "SUCCESS",
    "start_time" : "2014-02-15T00:32:40.575Z",
    "start_time_in_millis" : 1392424360575,
    "end_time" : "2014-02-15T00:32:42.022Z",
    "end_time_in_millis" : 1392424362022,
    "duration_in_millis" : 1447,
    "failures" : [ ],
    "shards" : {
      "total" : 5,
      "failed" : 0,
      "successful" : 5
    }
  }
}

スナップショットの確認

全てのスナップショットの確認する場合には...

curl -XGET "localhost:9200/_snapshot/my_local_backup/_all?pretty"

特定のスナップショットの確認する場合には...

curl -XGET "localhost:9200/_snapshot/my_local_backup/snapshot_1?pretty"

を実行する。

スナップショットの削除

スナップショットを削除する場合には以下のようにスナップショットを指定して削除する。

curl -XDELETE "localhost:9200/_snapshot/my_local_backup/snapshot_2?pretty"

普通のレストア

基本的なレストアは以下のように実行する。

curl -XPOST "localhost:9200/_snapshot/my_local_backup/snapshot_1/_restore"

こんな感じでレスポンス。

{
  "error" : "SnapshotRestoreException[[my_local_backup:snapshot_1] cannot restore index [restaurant] because it's open]",
  "status" : 500
}

はい。既に restaurant インデックスが存在する場合には上記のようにエラーとなる。

インデックス名を変えてレストア

では、インデックス名を変えてレストアする場合には以下のように実行する。

curl -XPOST "localhost:9200/_snapshot/my_local_backup/snapshot_1/_restore?pretty" -d '{
    "indices": "restaurant",
    "ignore_unavailable": "true",
    "include_global_state": false,
    "rename_pattern": "restaurant",
    "rename_replacement": "restored_restaurant"
}'

インデックス名を変更してレストアする場合には rename_pattern":"rename_replacement" は必須となる...ということで、以下のようにレストアが出来た。

f:id:inokara:20140215094318p:plain


スナップショットの仕組みの考察

スナップショットの仕組みを知る為には公開されているソースコードを読むのが手っ取り早いのはわかっているのだが...読めないので雰囲気的にこの辺かなと思われる部分を転載と考察。

スナップショット取得に関与しているであろう部分

elasticsearch/src/main/java/org/elasticsearch/snapshots/SnapshotsService.java の以下の部分がスナップショット取得に関与しているであろう部分。

    private void beginSnapshot(ClusterState clusterState, final SnapshotMetaData.Entry snapshot, final boolean partial, final CreateSnapshotListener userCreateSnapshotListener) {
        boolean snapshotCreated = false;
        try {
            Repository repository = repositoriesService.repository(snapshot.snapshotId().getRepository());

            MetaData metaData = clusterState.metaData();
            if (!snapshot.includeGlobalState()) {
                // Remove global state from the cluster state
                MetaData.Builder builder = MetaData.builder();
                for (String index : snapshot.indices()) {
                    builder.put(metaData.index(index), false);
                }
                metaData = builder.build();
            }

            repository.initializeSnapshot(snapshot.snapshotId(), snapshot.indices(), metaData);
            snapshotCreated = true;
            if (snapshot.indices().isEmpty()) {
                // No indices in this snapshot - we are done
                userCreateSnapshotListener.onResponse();
                endSnapshot(snapshot);
                return;
            }
            clusterService.submitStateUpdateTask("update_snapshot [" + snapshot + "]", new ProcessedClusterStateUpdateTask() {
                boolean accepted = false;
                SnapshotMetaData.Entry updatedSnapshot;
                String failure = null;
(続く...

ファイル全体を通して雰囲気として伝わってくるのは...

  • スナップショット時点の情報を snapshot_${スナップショット名} に書き込んでいる
  • 同じくスナップショット時点のメタ情報をどこかに書き込んでいる

んだろうなあというのは分かった。

snapshot と metadata

実際にスナップショットのリポジトリを見ると...以下のように snapshot_${スナップショット名} というファイルと metadata_${スナップショット名} というファイルが作成されているのが判る。

.
├── index
├── indices
├── metadata-snapshot_1
├── metadata-snapshot_2
├── snapshot-snapshot_1
└── snapshot-snapshot_2

1 directory, 5 files

これらはバイナリファイルで cat で見ると画面がグチャグチャになることがあるが lv でかろうじて中身を見ることは出来る。

lv snapshot-snapshot_1

以下のような出力になる。

ZV^A^@­^@Ë^S{"snapshot":{"name":à^@^R^R_1","version_id":10 ^@^\52,"indices":["restaurant"]," ^K^@t@B^FSUCCESS ? ^Q^Drt_ti@Y^Q1392424360575,"endà^G^X^B202 ^
total_shard c )^Bsuc n^Bsfuà^D^U^Dfailu <86>^B]}}

ちなみに snapshot-snapshot_1snapshot-snapshot_2 の差分を確認すると...

diff snapshot-snapshot_1 snapshot-snapshot_2

以下のように何かが違うらしい。

Binary files snapshot-snapshot_1 and snapshot-snapshot_2 differ

ちなみに metadata-snapshot_* には差異は無い。

ちょっと実験

snapshot_${スナップショット名} を削除してレストアしてみると...

{
  "error" : "SnapshotMissingException[[my_local_backup:snapshot_2] is missing]; nested: FileNotFoundException[/home/ubuntu/backup/snapshot-snapshot_2 (No such file or directory)]; ",
  "status" : 404
}

上記のようにレストアに失敗する。また、同様に metadata_${スナップショット名} を削除してレストアを試みると...

{
  "error" : "SnapshotMissingException[[my_local_backup:snapshot_2] is missing]; nested: FileNotFoundException[/home/ubuntu/backup/metadata-snapshot_2 (No such file or directory)]; ",
  "status" : 404
}

となりレストアに失敗する。

ということで

  • スナップショットを作成した際に作成される snapshot-${スナップショット名} ファイルは重要
  • 同じく metadata-${スナップショット名} ファイルも重要

最後に

  • curlAPI を叩くだけでスナップショットとレストアを簡単自在に操れるのは本当に素晴らしい