AWSアカウント間のDynamoDBデータ移行計画の記録(計画の実行と想定外の事象)

移行計画の作成と実施、そして想定外の事象
2021.06.28

お詫び

まずはじめにお詫びと訂正です。

今までタイトルを 「AWSアカウント間のS3, DynamoDBデータ移行計画の記録」 としていたのですが、ここに来て初めて「そういえば S3 オブジェクトは転送対象じゃなかった」ということに気づきました。大変失礼いたしました。

従って今回以降「AWSアカウント間のDynamoDBデータ移行計画の記録」 とします。

前回まで

前々回前回で転送方法、転送したデータの完全性検証方法を検討しました。

  • DynamoDB の転送対象テーブルを Export to S3 の機能でダンプする
    • 形式は DynamoDB JSON
  • DynamoDB JSON を分解して並列で移行先の DynamoDB テーブルへ登録する ECS で動作する Worker ソリューションを構築する
  • 移行元でダンプした DynamoDB JSON の Line 数と移行先のテーブルを Fullscan した件数を比較する
  • 移行元、移行先それぞれダンプした DynamoDB JSON データをデータベースのテーブルへ登録し、同一性を md5 を利用して確認する
  • S3 オブジェクトはあまりに多すぎるため作業時間が読めない上、同一性チェックも難しいことから対象外に調整

今回のテーマ

3 回目の今回は対応メンバーの役割分担と上記作業を効率良く行うためのスケジュール策定、及びその実行について記載していきます。

対応メンバー

今回の移行作業ではわたしを含めて 3 名がアサインされていました。それぞれの役割は以下になります。

メンバー名 役割
わたし とりまとめ、顧客調整、作業記録、作業可否判断、移行後のシステム立ち会い、S3 オブジェクト転送方法検証、ElastiCache転送方法検証
メンバーY DynamoDB 転送方法検証、当日の DynamoDB 転送作業
メンバーH DynamoDB データ完全性検証、当日の DynamoDB データ完全性検証作業、移行先新システムの初期運用、周辺システムの初期運用、移行後システム立ち会い

今まで記載してきた様々な検証については、 3 名でそれぞれ役割を分担して行ってきました。当日の作業実施もお願いしています。

移行作業のスケジュールについて

移行作業のスケジュールは、以下の要領で確定させました。

  1. まずは我々の方で、遅延、リトライが見込まれる作業のバッファを積んだ上で暫定スケジュールを作成
  2. 顧客と調整し、完全システムオープンの時刻から、各連携システムの検証時間を引いて転送完了デッドラインの時刻を逆算
  3. 転送完了デッドラインの時刻に確実に終わるように、作業開始時刻を逆算
    • 転送作業スケジュールにはバッファを積んでいるため、最悪のケースの作業時間で計画しています
  4. 作業開始時刻にすぐ作業が始められるよう、影響がない範囲で事前に準備できる作業をいれる

今回は、完全システムオープン時にはすべての連携システムが正しく動いてることを保証していなければなりません。そのため、最悪ここまでに転送が完了していないとアウトというデッドラインの時刻が重要になります。

万一リトライする場合においても、確実にそこに間に合わせるようにする、もしくは超過しそうな場合はできるだけ速やかに報告します。そのためには細かな進捗報告と時間調整、作業の効率化が必要です。

最終的なスケジュールは以下になります。

(見づらくてすみません・・・。詳細に関しては以下で説明します。)

重要データ α, β の転送処理が最優先です。

作業詳細

表の作業項目については以下になります。

移行元、移行先のアプリケーションをすべて停止し、データ転送を実行、その後移行先アプリケーションを再開させるというのが大雑把な流れです。

1. リクエスト数確認

DNS の設定を変更し、対象ドメインのリクエストをメンテナンス画面へ。移行元システムへのリクエストを遮断します。移行元システムへのリクエストがなくなったことを確認し、蛇口がしまってることを確認します。

2, 3. 移行元、移行先システムの停止

移行元、移行先システムのデータ静止状態を保つために停止させます。移行元の ElasticBeanstalk の EC2 インスタンスを停止、移行先の ECS のタスク数を 0 に変更します。

4. DynamoDB データ転送準備

転送ソリューションの Worker, SQS 等のリソースを CDK によって構築します。この作業は必要な AWS リソースの準備のみなので、データ転送対象へ影響を与えません。夜間の作業ですが、念の為事前に構築後軽く動作チェックを行いたいため、作業当日の 15 時に実行することにしました。

5. 移行元 DynamoDB データを S3 へ Export

すべての転送対象のテーブルに対して、 Export to S3 を実行します。それぞれのテーブルは独立して実行されるため、すべて同時に実施で問題ありません。スケジュール上かなり大きく取っているため、ここで時間的に少し巻きで進行できる想定です。

6,7. 転送作業

2 回に分けて転送作業を実施します。重要データα, β は完全性検証の対象であるため、最優先で転送を実行します。これらの転送作業が完了してから、もう一つのログイン情報を転送する手はずです。

8,9. 重要データα, β の完全性チェック

対象のデータが転送完了した後、ログイン情報の転送を実施しつつ、並行して完全性検証を実施します。万一ここで差分が出た場合は、ログイン情報の転送と並行してそれぞれのテーブルへの再投入を行います。

まずは、移行先で Export to S3 を実行しデータのダンプを取得します。

10. RDB へのデータ入力

移行元のダンプデータを S3 のクロスアカウントアクセスで取得、移行先は先程の手順で取得したダンプデータを EC2 インスタンス内に構築した Postgresql へデータ投入します。

投入用に JSON Line を読み込んで SQL で投入する Python スクリプトを実装し、これによってデータの投入を行います。

11. データ比較の実行

SQL を 2 本実行し、件数の差分とデータの同一性チェックを行います。ここで差分が出た場合、いずれにせよ再投入が必要なため、差分件数を把握した上で、再投入対象の JSON Line データを作成します。

差分件数を把握した時点で、並行して関係者へ連絡し、現状の説明と再投入及び再チェックに最大どれくらいの時間がかかるかを報告します。必要であれば、メンテナンス時間の延長のアナウンス調整、作業を中止し撤退の判断をお願いします。

12, 13. 移行先システム起動

データの転送が完了すると、新システムを起動します。まずは最小限の構成で起動し、正常にアプリケーションが起動するかを確認します。最低限動作チェックが終わり、問題がなければ本番相当の台数へスケールします。

これで全体の作業スケジュールは概ね決まりました。

計画の確定

必要な作業時間をプロットしたので、これを元に作業開始時間を決定します。

上記スケジュールのシートにはすでに時間が記載されていますが、実際には、サービスオープンの予定時刻から各連携システム、対向システムの動作試験の時間を差し引いて、転送作業のデッドラインの時間を逆算しています。さらに決定した転送作業の完了必須の時間(デッドライン)から、作業予定時間を差し引いたものの時刻が転送作業開始時間となります。

我々の転送作業スケジュールとしてはこれで問題ないのですが、作業当日、予告なしにいきなりシステムを落とせるわけではありません。転送作業に入る前には以下のような準備が必要になります。

  • 各連携システムをメンテナンスモードにする
    • オンラインシステムだけではなく実店舗等のオペレーションも含まれます。
  • 深夜帯に実行されるバッチシステムのスケジュール停止
  • エンドユーザーへのメンテナンス告知

これらを事前に行うためのスケジュールも別途組んでいただきました。さらにメンテナンス当日は、我々の転送作業開始より 2 時間以上前から関係者の方々には準備いただいていました。皆さんのご協力あってのメンテナンス作業です。感謝しかありません。 *1

計画の実施

当日の体制

はじめに当日の体制について軽く触れておきます。

  • 顧客受け入れ担当: 2名(さらに対向システム連携テスト時には、〜5, 6名規模程度)
  • 転送作業担当: 事業開発部タスクフォースメンバー(わたし以下二人の合計3名。翌日の監視では時間差で 2 名)
  • CX の連携システム担当: CX 部の担当者2名(翌日のシフト交代でさらに 2, 3 名)

途中で時間シフトの関係で入れ替えがあるとはいえ、多くの方がこの転送作業に関わっています。

連携ツール

メンテナンス作業中において細かい報告、事象の素早い報告が必要なため以下を準備しました。

  • Slack: メンテナンス作業用のチャンネルを作成し、関係者全員を招待。状況のサマリ等を共有。
  • Spreadsheet: タイムスケジュールの共有とメモに利用
  • Zoom: 顧客との連絡。各作業のポイントポイントでの進捗状況報告。調整
  • Meet: 主に実際に作業する社内メンバーとの連絡。事業開発部、CX横断で作業に関わる全員参加。込み入った相談や想定外の事態への対応のその場での判断など

基本的に、Slack と Zoom による顧客とのやり取りは、私が担当し作業メンバーには自身のタスクに集中してもらうようにしました。

作業実施のタイムライン

作業当日ですが、実際のタイムラインは以下のようになりました。作成した計画をおよそ実際の時間にプロットし直しています。

最終的には 30 分近く巻いた状態で作業完了しています。全体的にバッファの消費も最小限です。

ただし、ある一つの作業を除いては。

実際の作業時間の記録です。

時間 イベント メモ
23:05 オンラインシステム全閉局作業完了
23:08 移行元システム(EB)1台体制へ変更
23:15 移行元システム(EB)完全停止 RollingUpdate Policy を Disable に。復旧の際はEnable にする
23:18 SQS, SNS Subscription 設定
23:20 DynamoDB Export 開始 2021-05-21T23:21:33.767000+09:00
23:40 Import 作業着手
00:15 検索サービスに大量アクセスが残っていることを確認 メンバーが確認。※1
00:18 オンラインシステムを完全停止 CX側担当者
00:55 重要データ β の転送がうまくいかない ※2
01:06 重要データ β の転送を再送
01:37 ログイン情報の転送元データの修正 計画した手順にない作業
01:45 ログイン情報の転送開始
02:05 ログイン情報転送完了
02:23 重要データ β 3度目の再送(修正)
02:43 重要データ β 転送完了
02:45 移行先重要データ β Export 開始
02:58 移行先重要データ β Export 完了
03:15 移行先システム最低限起動
03:23 移行先システムを本番相当へスケールアウト

重要データ β の転送でトラブルが発生し、合計 3 回転送のやり直しを実行しています。想定外の事象が発生した箇所に関しては 米印 にて記載しました。それぞれの現象を以下に記載します。

※1 検索サービスへの大量アクセス

移行元のシステムに依存している検索サービスがあるのですが、こちらへ作業中にも関わらず依然として大量のアクセスがあることがわかりました。本来、この検索サービスを利用する各連携システムはすべてメンテナンスモードに入っており、アクセスがほぼないことを想定していたため、想定外の事態です。

このサービスを利用している管理用端末があるのですが、そちらのアプリケーションが定期的にポーリングを実行しているのが原因でした。検索サービスへポーリングするものの、検索サービスは依存しているシステムがメンテナンス状態になってしまっているため応答ができずエラーで返却。管理用端末はエラー復旧までずっとポーリング処理をリトライし続けるという状態でした。

実際には移行元システムへ直接アクセスがあるわけではないので、転送作業への影響はないのですが、検索サービスへ大量のリトライアクセスが施行されているため、膨大なエラーログが記録されます。このままでは転送作業が完了するまで、余分なエラーログの記録でリソースを消費してしまいます。

そのため関係者と協議の上、一旦管理用端末用のアプリケーションを停止いただくことにしました。

※2 重要データ β の転送作業がうまく行かない

今回最大の想定外の事象です。実際のタイムラインの表の赤い箇所がありますが、その部分がこの事象によって影響した範囲になります。転送時間が大きく伸びてしまったことにより、いくつか作業順序の組み換え、その場での対応の検討と実施が必要になりました。

本来、想定外の事象で事前に準備した作業手順以外の事象が発生した場合は、即刻作業を中断すべきです。今回たまたまうまくいきましたが、これは例外です。 「お客様と連携し、事象を説明した上で「こういった作業で再投入を行います。何時までにこれでダメであれば撤退します」といった内容を説明し、その場で内容を理解いただけていたこと」、「データ構造とデータ転送ソリューションを熟知しているメンバーがたまたまいたこと」、「比較的単純な作業のみで解決可能だったこと」、「冪等性が確認されている作業であり、何度実施しても結果がおなじになることがわかっていたこと」。こういった条件が揃っていたことから例外的に行ったことであり、本来は十分に検証を行い、手順として問題がないことを確認してから実施すべきです。

重要データ β の転送作業で発生した事象について

重要データ α, β はそれぞれ完全性検証の対象であることは、何度も説明したとおりです。そのため、2 つのデータは最優先で転送作業を開始しています。重要データ α に関しては想定通り 30 分ほどで完了しています。(タイムラインには記録されていないですが・・・)

しかし、肝心の重要データ β の方は Import の開始作業から 1 時間以上経過しているのに終わっていません。重要データ α, β はそれぞれ同じ hashId をパーティションキーに持っているデータで件数は完全に一致しています *2。そのため件数の違いによる処理の遅延ではないようです。明らかにおかしいため何が起きているかを調査します。

DynamoDB の対象テーブルの Write Capacity Unit の推移

重要データ α は転送時、最大で 11000 ほどの WCU までスケールしているのを確認しています。しかし、重要データ β のテーブルのメトリクスを確認したところ、 3000 前後で頭打ちしています。

α, β 共に全く同じ転送ソリューションを利用しているため、処理による違いはないはずです。

SQS の Inflight Message の確認

前回の記事で記載したように、 SQS を利用した転送ソリューションを構築しています。実際に登録するデータは、 SQS に一度キューイングされてから処理しています。

そこで、取り込み、分解をしている Producer の SQS と、実際にデータを登録している Worker の SQS メッセージのメトリクスを確認します。

Worker 側の SQS には Queue に入っているメッセージはほぼ0 、Inflight Message には数十程度が記録されています。また、Producer 側の SQS には Queue に入っているメッセージは 0, Inflight Message には 4 が記録されています。

これだけ大仰な転送ソリューションを組んでいる割には、処理しているメッセージが少なすぎではないでしょうか・・・? 🤔

転送ソリューションのアプリケーションログを確認

転送ソリューションのログを確認したところ、同じデータが 3 回書き込まれているログがありました。すでに登録済みのデータを再度読み込んで登録しているようです。これでは終わるはずがありません・・・。

SQS の Visibility Timeout 設定を 30 分と設定していたのですが、これを超過したため再度メッセージが見えてしまい、待機中の別の Worker が未処理のデータとして、すでに Worker で処理中のファイルを再登録しはじめてしまったと考えられます。

Amazon SQS 可視性タイムアウト

つまり、本来長くとも 30 分で完了するはずの処理が完了できず、 Visibility Timeout を迎えたメッセージが再度取得可能になり、別の Producer が新たなメッセージを受信したと思いこみ、処理中のものと全く同じファイルの処理を開始していました。これでは永遠に処理が完了しません。 *3

何が原因か

上記メトリクスやアプリケーションログを確認し、 Producer の箇所がボトルネックになっているというのがわかりました。

では、なぜ事前の想定と異なり Producer が並行処理がスケールしていないのでしょうか?

時間内に作業完了できるよう回避する方法はあるのでしょうか?根本原因を探り解決、または回避する必要があります。

そろそろ長くなってきたので次回へ。

上記の状況から、なぜ Producer がスケールしなかったのか、根本原因は何なのか、を是非考えてみてください。 *4

まとめ

過去 2 回で転送手順の確立とデータ完全性の検証について確認しました。

今回は、それらをどのような順序で、どの作業を並行して行うなどを考慮して、具体的なタイムスケジュールを作成するまでをまとめました。

実際、このスケジュールの作成は一回で完全版ができているわけではなく、2 週間ほど細かい調整を経た上で決定しています。転送作業のみであれば単純なのですが、実際にはお客様のビジネスを停止した上でメンテナンスに入るため、ビジネスサイドの調整や各関連システムを開発している開発会社との調整も必要です。

綿密に読み合わせを行い、このチェックポイントでこうなった場合は、それぞれこういった行動を行うといった認識合わせも行いました。こうした綿密な計画のもと実施していますが、想定外の事象(よりにもよって転送作業で一番重要な部分)が発生しており、現実を完全に想定し切るのは難しかったという印象です。

結果として計画の 30 分前に作業完了できていますが、様々なケースのアクションを事前に準備しておくことで、想定外の事象でも迷いなく決断できたことは大きな要因の一つかと思います。

次回が最後の予定です。

最大の想定外事象の根本原因とその対処・回避方法について記載する予定です。あと一本お付き合いください。

脚注

  1. こういった事情もあり、万一の場合の手順は様々なバリエーションを用意していましたが、もし撤退した際の影響範囲、機会損失に関しては計り知れない影響があることを重々認識していました。胃が痛い。
  2. 重要 β が著しくデータ量が多いとかそういうわけではない
  3. Visibility Timeout がギリギリすぎるというのもあるかもしれません。処理に 20 分弱かかることは想定済みであったので。
  4. 実際、僕らも上記くらいの情報しかない状態だったので状況としては同じような感じです。