APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

Datastore Import/Exportの紹介(1/2)

始めに

先進サービス開発事業部の山岡です。

私がバックエンドを開発しているNEIGHBORSはAppEngine(Go)の上に構築されており、データベースはCloud Datastoreを使用しています。

Datastoreはスケーラビリティに優れたNoSQLデータベースで、容量が無制限、Entity(RDBMSでいうところのレコード)が増えても性能が劣化しない、各言語にラッパーがあり手軽に利用可能等といった特徴があります。また課金が保管容量とR/Wオペレーション数であり、実際の利用が少なければ殆ど費用が発生しないのは特にNEIGHBORSのようなミニマムスタートにとってありがたいポイントです。

今回はこのデータベースのバックアップ・リストアに関する知見を共有します。

管理コンソールからのバックアップ・リストア

本題に入る前に前世代の仕組みについても触れておきましょう。

GCP -> データストア -> 管理 から下記写真のような管理コンソールへアクセスすることができます。ここにはバックアップを実行できそうなボタンがありますが、画面上部に表示されている通りこれは既にDeprecatedで2019年に廃止予定となっています。

f:id:ryo-yamaoka:20180427183014p:plain

この旧世代のバックアップ・リストア機能を使うとMapReduce for AppEngineという仕組みを使って実行されますが、これは既にレガシーなものと見做されておりGCPのメニュー画面には表示されておらず積極的に使う理由はありません。

実行基盤はAppEngineのTaskQueueになっておりDatastoreのR/W以外にもインスタンスの課金が発生してしまいます。更に比較的高頻度に(正確にカウントはしていませんが毎月数回程度?)ジョブが失敗します。単に失敗になって終わってくれればまだ良い方で、異様にスループットが低くなってしまったり延々Datastoreへのアクセスに失敗し続けていたりと地味にお財布にダメージを与えられてしまいます。一応ジョブを破棄した上でリトライをかければ正しく終わってくれるので割りきってしまうのもアリといえばアリですが……。

この辺りの対策としてAppEngineのCronで所定の時間に正しく終わっていなければリトライをかけたりといった処理を実装したのですが、最早死にゆく機能なので割愛します。

Import/Export

さて本題です。

2018年3月に新しい手段であるImport/ExportがGAリリースされました(日本語記事)。

Import/ExportはDataflowをバックエンドに使用しているようですが(某コミュニティ識者談)、課金はあくまでDatastoreのR/W代金だけです。また記事にある通りスループットも大幅に伸びており大容量データの処理にかかる時間が短縮されています(現状NEIGHBORSのようにたかだか数百万Entity程度では然程違いは感じませんでしたが)。

Export(バックアップ)

下記のような書式のコマンドを使います。何を指定しなければならないかは大体見た目通りですしオプションも少ないのでヘルプコマンドを参照すれば十分わかるかと思いますので、ハマりやすいポイントに絞っていくつか補足します。

gcloud datastore export --kinds="xxx,yyy,zzz" gs://example-datastore-export/ --async

Export先のGCSについてはDatastoreと同じリージョンのバケツでなければなりません。何らかの理由でバックアップ先とリストア先が別リージョンの場合はGCSの転送機能を使ってコピーしてやるのがいいでしょう。

--asyncは非同期に処理を実行するコマンドで、バックアップはそれなりの時間がかかるケースが多いでしょうから大抵これを付けることになるかと思います。1,800秒を超えるとその時点でエラーとなりプロンプトが返りますが処理はそのまま継続されていますのでご安心下さい。

進行中の処理を確認する場合はgcloud datastore operations listで参照することができますが、処理が終わるとこのリストからは消えてしまいます。これを見るにはgcloud datastore operations describe projects/example-project/operations/XXXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZZZで確認することができます(末尾に付いているパラメーターはバックアップ開始時に払い出されるname:の部分です)。

バックアップには一点注意しなければならないポイントがあります。--kindsの指定を省くと全Kindをバックアップしてくれるのですが、この方法でバックアップした場合は個別Kind毎のImport(リストア)ができず全部書き戻さなければなりません。Kindを指定したリストアをする必要がある場合は(大抵あるでしょうけれども)面倒ですが別個にKindを指定してあげなければなりません。

またリストア時に必要となるGCSへの出力先がgs://example-datastore-export/2018-04-04T05:55:36_58240/2018-04-04T05:55:36_58240.overall_export_metadataといった形で払い出されますのでこれを控えておく必要があります。

Import(リストア)

下記のような書式のコマンドを使います。

gcloud datastore import --kinds="xxx,yyy,zzz" gs://example-datastore-export/2018-04-04T05:55:36_58240/2018-04-04T05:55:36_58240.overall_export_metadata --async

--asyncについてはExportと同様なので割愛します。

Export時にKindの指定をバラバラで行なっていればここでの--kindsは個別に指定することができます。ImportもExportと同様にオペレーションの様子を参照することができます。

トラブル事例:Importできない

NEIGHBORSの環境では取得したバックアップをリストアできないという事象が発生しました。Import/Exportは上手くいこうが失敗しようがStackdriverにログが殆ど出力されないため途方に暮れてしまい、やむを得ずサポートにチケットを起票して対応して頂きました。詳細は割愛しますが色々とやり取りした結果無事に問題は解決できました。結局詳細な原因は貰えませんでしたがどうもExport時の挙動にバグがあり正しくバックアップできていなかったようです。

一つ参考になったことは、データが正しくExport出来ているかチェックする際はバックアップデータをBigQueryにロードしてみるというテクニックです。実際のやり取りの中でもこの操作を要求され結果を伝えましたので、同様の事象に遭遇した場合はこの結果を添付して起票すると話が早いかもしれません(今回は直接原因の解決に繋がりませんでしたが)。

所感

以前の管理コンソールより簡単にバックアップ・リストができるようになりオペレーションが楽になったと思います。反面、特にKindの指定などで不器用な部分もやや見受けられますのでユーザー側で少し慣れが必要です。

今回の記事では定時バックアップについては触れませんでしたが、これも実現できますので次回の記事にて紹介したいと思います。