はじめに
数TB規模のオンプレ資産を Google Cloud(Cloud Storage と Cloud Spanner)へ移行するプロジェクトに参加しました。設計書レビューで顧客から繰り返し詰められたのが「件数が合えば終わり、ではない」「停止時間はどう読むのか」の2点です。
派手なアーキテクチャ刷新ではなく、設計段階で押さえておけば後工程で焦らずに済んだ勘所を、ファイル移行とDB移行の両面から整理します。これから GCS / Spanner への移行を控える方の参考になれば幸いです。
Part 1: ファイル移行 — 停止時間ゼロに近づける rsync 二段構え
問題発見: シングルカット移行は停止時間が"読めない"
オンプレのアプリケーションサーバ群から Cloud Storage へ、数百万ファイル・数TB規模のコンテンツを移します。初版の設計書では「サービス停止 → 一括 rsync → 動作確認 → 切替」というシングルカット構成でした。
レビューで指摘されたのは「実測ベースの停止時間根拠がない」点。事前検証で完走時間を計っても、当日のネットワーク負荷次第でブレが大きく、SLA上飲める停止枠に収まる保証ができませんでした。「最悪ケースで何分かかるか答えられない移行計画は通せない」というのが顧客側の本音です。
解決設計: rsync を「事前同期」と「差分同期」に分割する
gcloud storage rsync をフェーズ分割しました。
| フェーズ | タイミング | サービス状態 | 転送内容 |
|---|---|---|---|
| A. 事前同期 | 切替日の数日前から定期実行 | 商用稼働中 | 全量(初回)→ 差分(2回目以降) |
| B. 当日差分同期 | 切替当日のサービス停止後 | メンテナンスモード | フェーズA以降の差分のみ |
gcloud storage rsync はファイルサイズと更新日時で差分判定するため、変更されていないファイルは2回目以降スキップされます。これによって当日の転送量を、おおむね「直近24時間ぶんの更新差分」まで圧縮できます。
Before / After(停止時間の試算)
| 方式 | 当日転送量 | 想定停止時間 | SLA枠への収まり |
|---|---|---|---|
| シングルカット | 数TB | 数時間〜(読めない) | 不可 |
| 事前同期+差分同期 | 数十GB(差分のみ) | 分オーダー | 余裕 |
設計上のポイント3つ
-
再実行可能性を前提に組む
フェーズAは複数回流れる前提です。1回目で全量、以降は差分のみが流れるので、定期実行スケジュールに乗せても無害。むしろ「事前同期は何度でもやり直せる」という性質が、運用上の心理的安全になります。 -
削除フラグの扱いを慎重に
--delete-unmatched-destination-objectsを素直に付けると、事前同期期間中にクラウド側へ何らかの理由でアップロードされたオブジェクトが消えます。「移行期間中はクラウド側に書き込まない」運用と組み合わせるか、削除はフェーズBのみで有効化するかを設計書に明示しました。 -
権限とライフサイクルを切替前に検算
事前同期で先行アップロードされたオブジェクトに、商用切替時のIAMポリシーやライフサイクルルールが意図通り効くかは、必ず切替前に1ファイルでも実機確認します。「同期は完璧だがACLが噛み合わず読めない」は実際に起き得ます。
検証設計: find × gcloud storage ls × md5sum の三点突合
「同期したからOK」では設計書として通りません。検証手順は次の三段で組みました。
# オンプレ側: 相対パス + サイズの一覧
find /mnt/contents -type f -printf '%P\t%s\n' | sort > onprem.tsv
# Cloud Storage 側: 同等情報を抽出して整形
gcloud storage ls -lR gs://bucket/contents/** \
| awk '/^[^TOTAL]/ {print $NF "\t" $1}' | sort > gcs.tsv
# 一覧全体を1ハッシュに畳んで突合
md5sum onprem.tsv gcs.tsv
ポイントは find の -printf '%P\t%s\n' でルートを除いた相対パスとバイトサイズを出力すること。Cloud Storage のオブジェクト名と直接突き合わせやすい形になります。
一覧をソートしてからファイル全体の md5sum を取れば、行単位 diff を取らずに「同一かどうか」を1コマンドで判定できます。数TB規模だと全ファイル個別のチェックサム取得は現実的でないので、「一覧(パス+サイズ)の整合を高速チェック → サンプル抽出で個別ハッシュ比較」の二段構えに落ち着きました。
Part 2: DB移行 — PostgreSQL→Cloud Spanner で「件数一致」は出発点
問題発見: 顧客レビューで突き返された3観点
PostgreSQL から Cloud Spanner への移行設計書を初版で出したところ、顧客レビューで以下3点を指摘されました。
- 検証方法の拡充 — テーブル件数とPK一致だけでは検証として弱い
- 移行時の制約・依頼事項の明記 — メンテナンスモードへの切替タイミング、データ静止点の定義が曖昧
- 役割分担・作業時間の記載 — どの工程を誰が、何分かけるのか不明
要するに「設計書として読み手が意思決定できない」状態だったわけです。特に1番は耳が痛い指摘でした。
解決設計1: 検証を5層構成に拡張
最終的に検証章を以下の5層構成に組み直しました。
| レイヤ | 内容 | この層で検出できる事象 |
|---|---|---|
| 1. 件数検証 | テーブルごとのレコード件数比較 | 行漏れ |
| 2. PK一致検証 | PK集合の比較(ソート後md5sum等) | 抜け/重複 |
| 3. データ型変換検証 | 型変換ルールに沿った代表値サンプリング比較 | 型差異起因の値破損 |
| 4. 業務操作検証 | アプリ経由の参照/更新シナリオ実施 | アプリ層で初めて顕在化する不整合 |
| 5. 性能検証 | 主要クエリのレイテンシ確認 | Spannerのインターリーブ/インデックス設計の妥当性 |
特に効いたのは3層目と4層目
PostgreSQL の TIMESTAMP WITH TIME ZONE と Spanner の TIMESTAMP、NUMERIC の精度・スケール差、TEXT ↔ STRING(MAX) のソート挙動差など、件数とPKだけ見ていれば必ず素通りする差分が、データ型変換検証で炙り出されます。
さらに業務操作検証(4層目)は、アプリ側のORMやドライバが想定する型と Spanner 側の実型のズレを実走で検出する最後の砦になります。「SELECT を流して値が一致」と「画面に正しく表示される」「業務処理が完走する」の間には、地味だが致命的な距離があります。
解決設計2: 制約事項と役割分担を表で明文化
「メンテナンスモードへの切替は顧客作業」「データ静止点(書き込み停止)の確認はベンダー作業」のような責任の境界を工程ごとの表で記載しました。想定時間も併記することで、レビュー時に「この工程、本当に15分で終わるんですか?」という具体性のある議論が成り立つようになります。
ここを書かないと、レビューが「何となく不安」で終わってしまい、設計書としては最悪のステータス(「再レビュー」)に落ちます。
解決設計3: 複数ツールが登場する設計書では役割分担を明記する
スキーマ生成は spanner-migration-tool schema で、データ投入は別の自作Python移行ツールで、という構成にした際、初版ではどのツールが何を担当するかの境界が曖昧でレビュー指摘を受けました。
[Before] 「移行ツールでスキーマとデータを移行する」
→ 読み手「で、結局どっちのツールが何やるの?」
[After] ツール別の責務表を1枚追加
| ツール | 入力 | 出力 | 責務 |
|---|---|---|---|
| spanner-migration-tool schema | PG DDL | Spanner DDL | スキーマ変換のみ |
| 自作Pythonツール | PG レコード | Spanner レコード | データ投入のみ |
たった1枚の表で読み手の混乱は激減しました。
Part 3: 設計書の整合性を崩さないチェックリスト
移行設計書は、対象が途中で変わると整合性が一気に崩れます。「移行不要になったテーブルが検証対象一覧に残っている」「移行先バケットが減ったのに移行フロー図に古いバケットが残っている」は、レビューで必ず突かれます。
移行対象を変更する際に連動更新すべき4箇所を、チームのチェックリストに固定化しました。
- 移行不要テーブル/対象一覧
- 移行先バケット/スキーマ一覧
- 移行フロー図(手順)
- 検証対象リスト
1箇所だけ更新して残り3箇所を忘れる、というのが設計書全体の矛盾を生む最頻パターンです。差分PRレビュー時もこの4点を機械的にチェック観点に入れることで、整合性事故を未然に防げました。
おわりに
オンプレ → Google Cloud 移行で繰り返し顧客レビューに問われたのは、結局のところ次の2点に集約されます。
- 停止時間を「読める形」に分解する — シングルカットではなく事前同期+差分同期で、当日の不確実性を圧縮する
- 件数一致を出発点にする — データ型変換と業務操作の2層を必ず重ねる
派手な技術ではありませんが、設計書の質は最終的にこの「分解の細かさ」で決まる、と痛感したプロジェクトでした。
同じく GCS / Spanner への大規模移行を控えている方にとって、レビューで詰められる前に潰せる観点として参考になれば幸いです。