はじめに
- elasticsearch 1.0.0 が正式にリリースされたので改めて Snapshot と Restore 機能を試してみる
- スナップショットの仕組みについて少しだけ深堀りしてみる
操作
EC2
インスタンス上に構築した elasticsearch 1.0.0
リリース版を利用して操作する。また、データ自体はライブドアが提供しているこちらのレストランデータを利用する。
上図の restaurant
インデックスを題材に Snapshot
と Restore
機能を試してみる。ちなみにリクエスト内の ?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"
は必須となる...ということで、以下のようにレストアが出来た。
スナップショットの仕組みの考察
スナップショットの仕組みを知る為には公開されているソースコードを読むのが手っ取り早いのはわかっているのだが...読めないので雰囲気的にこの辺かなと思われる部分を転載と考察。
スナップショット取得に関与しているであろう部分
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_1
と snapshot-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-${スナップショット名}
ファイルも重要
最後に
curl
でAPI
を叩くだけでスナップショットとレストアを簡単自在に操れるのは本当に素晴らしい