大規模データ移行の失敗を防ぎたい。計画やプログラム、インフラの注意点と、ありがちなこと

仕事柄、大規模なデータ移行を何度か経験してきました。

データ移行、特にDBのマイグレーションでもなく、
システム移行のときのようなデータ構造の変更を伴う際には気をつけることがたくさんあります。

クラウドではだいぶ楽になりますが、
特にオンプレミスで検討せざるを得ない皆さんに気をつけないといけない点を共有します。

#スケジューリング編

##最初から検討し始めよう

開発プロジェクトにおいて[システム移行だけで4割の工数がかかる](http://itpro.nikkeibp.co.jp/article/COLUMN/20080303/295281/)と言われています。
しかし、新規システム部分の開発で頭が一杯になっていると、重要度の割に移行部分が後回しにされがちです。
移行用プログラム、移行用サーバ手配はもちろん、新規、既存システムへの影響も検討しないといけません。
できればプロジェクト開始時から人をアサインして計画を立てていきましょう。
移行自体が一つの開発プロジェクト相当です。頑張りましょう。

###ありがちなこと
* 後半になって移行計画を立てたら、計画上どう考えても間に合わないので延期になった
* サービスインまでの計画に移行用プログラム開発の時間がなく、結果バグだらけ、移行作業の属人化などなど
* 移行部分の各リソースが確保できず、緊急で手配して予算超過した

##移行タイミングを分割しよう

規模が大きい場合、一度に全部移行するより、数回にわけて徐々に移行しましょう。
まとめて一回にしてしまうと失敗時のリカバリに時間がかかります。
データに限らず一般論として、規模が大きなものはできるだけ分割して移行したほうがよいです。

ビッグバン方式は控えめに。

### ありがちなこと
* トラブルでシステム停止時間が当初想定の数倍になった
* 大きすぎてそもそも計画が立てることが難しい

##切り戻し計画を立てよう
残念ながらトラブルは発生します。すぐに戻せるよう計画を立てましょう。
いつまで頑張るか、あらかじめ決めておき、その時間を過ぎたら躊躇なく戻しましょう。

人生諦めが肝心です。

###ありがちなこと
* トラブル対応がダラダラと伸びて、影響が大きくなる
* 関係者への周知が漏れる
* 移行中に更新されたデータが切り戻しの際に漏れてデータ欠損発生

##リハーサルしよう
新、旧両方の仕様が必要で、移行用ツールも準備しないといけないデータ移行は課題が山積みです。
本番同等のリハーサルで課題を潰しましょう。

最低2回はしたほうがよいです。1回目は問題洗い出し、2回目は1回目の問題が解決できたか。
切り戻しについてもリハーサルすることを忘れないように。
### ありがちなこと
* 当初に見積もった作業時間より大幅に伸びる
エラーが出まくる
* サーバにつながらない
* 当日の移行作業タスクに穴がある
* リハーサルできなかった部分でサービスイン当日に大失敗
* リハーサルまでに移行プログラムのテストまで終わらせていない

##みんなを巻き込もう
データ移行ではほぼ確実にデータ修正が入るので、
既存システムの利用者に影響が出ます。
利用者を巻き込みましょう。

また移行用プログラムを動かすだけでも、
インフラ、ネットワークエンジニアの力を借りることになります。
早めにお話しましょう。
###ありがちなこと
* 利用者側の改修が直前になって発生
* インフラの手配が遅れ、実行環境が準備できずスケジュール遅延


#既存データの内容編

##既存データを一通り目視確認しよう
既存データには、必ず当初の想定から外れたデータが入っています。
これは自然の摂理です。

全件確認が最も確実ですが、
件数からみて難しそうならサンプリングや統計をとってデータを目視確認しましょう。
実際のデータを一覧化して眺めると、いろいろなことがわかってきます。
###ありがちなこと
* 移行プログラムを流すたびにエラーが起きる
* データを確認したところ既存システムのバグが新たに見つかり時間を取られる
* 謎の値がやけに多い

##想定を定義して全件確認しよう
例えばIDなら文字列型...だけではなく、
桁数、IDの形式といったものを定義し(型システム..?)、全データをチェックしましょう。
Check制約が効いていたとしても、
「このデータがこれなら、こちらのデータはこうなってないといけない」といったものもあるかもしれません。
全カラムに対して定義内に収まるか確認することをおすすめします。
###ありがちなこと
* 桁数がおかしいデータがある
* データが空
* なんじゃこりゃ

##データの分布（濃度）を確認しよう
各カラムにおいて、ある特定のデータがやたら多いことがあります。
想定より多い場合、特殊な用途として使われている可能性を考慮しないといけません。
仮の例として、
「顧客IDのうち上3桁000が多い。実は、普段はE2Cの業務だが法人対応のため法人顧客000にして運用している。」
といったように、機能不足を運用でカバーしている可能性があります。
他にはデフォルト値や管理アカウントを指しているかもしれません。
その他の問題として、データが偏っていると、新しいシステムでの検索速度に影響が出てしまいます。
インデックス(または相当のなにか)を使った動作が遅くなるためです。
###ありがちなこと
* ばらつきのあるはずのデータがばらついていない
* 選択式のデータの比率が想定と異なる


##空データ、デフォルト値
デフォルト値や空文字、空白、nullについて、現行システムと新システムで扱いが違う場合は要注意です。
動作が変わるのに誰も気づいていないかもしれません。
###ありがちなこと
* デフォルト値が新旧で異なるが誰も気づいていない
* 空文字やnullの扱いが新旧で異なるが誰も気づいていない


##文字集合に気をつけよう
既存と新規のデータベースとプログラム、加えて移行プログラムではどんな文字を扱うか答えられますか？
日本語？日本語ってなんだろう。
認識を合わせないと文字化けが発生してしまいます。
なお、コンソールやエディタ、フロント画面で表示されるテキストは、想定通りとは限りません。
###ありがちなこと
* CP932で拡張された文字が移行できない(丸囲いの1、「﨑」といった一部の異体字、「☃」など)
* 絵文字🍣などUnicodeのいろいろな闇文字が移行できない
* エディタ上の表示とバイナリ表示が異なる
* フリー入力欄として登録済みの文字が。。

##せっかくなのでデータをきれいにしてみよう
普段の業務ではおかしいデータを直す機会はなかなかありません。
せっかくなのでデータ移行のタイミングでクレンジングしてみましょう。
###ありがちなこと
* 本番データなのにテスト時にできたデータだらけ
* よくみたら検証用データなので消せない


#移行プログラム編
##開発、ステージング環境を用意しよう
移行プログラムもそれ自体テストが必要です。
また、既存システムの開発とステージングのデータも移行するべきです。
環境を用意しましょう。

##データ移行時間を見積もろう
データ移行プログラムの実行完了まで果たして現実的な時間で終わるでしょうか？
開発やステージングから見積ったとしても、データ件数や偏り、サーバースペックも違うので参考になりません。
チューニングは必須ですし、プログラム実行より前にできるタスクを洗い上げて移行時間を短縮しましょう。
###ありがちなこと
* 本番だとデータ移行プログラムが数十時間かかる
* データ移行日より前に作業可能なタスクを洗い出していない

##パフォーマンスをあげよう
移行プログラムはOLAP的な大容量データ操作になるため、
WebアプリケーションのようなOLTP処理とポイントが異なる部分があります。
地道に改善していきましょう。プログラムを並列に動かしてもOKですよ。
###ありがちなこと
* データ移行元、移行先、移行用環境についてOLAP処理向けのパフォーマンスチューニングしていない
* プログラム上で全データを一括で取得してしまい、メモリがパンクする
* 移行用プログラムで新しく必要になりそうなインデックスがデータ取得元にない
* データ取得元で全件ソートしている。ソート不要なのにソートしている
  * 特にMySQLの場合、ソート時に使う一時テーブルの使用量が多すぎると  
  一時テーブルがMyISAM(5.7からはInnoDB)化し、ディスク容量を激しく消費するリスクがあります
* 1つのトランザクションで全データを一括投入してしまい、処理が終わらない

##ログを厚めに出そう
時間がかかるデータ移行処理。
ログがないと今どこまで進んだのかわかりません。
エラー時にどこで間違ったのかもわかりません。
移行プログラムに関しては、ログローテーションがほぼ不要なこともあり、
本番でもINFOレベルのログを全部出すつもりで。
###ありがちなこと
* ログがなくて今何が起きているかわからない
* ログがなくて何が起きたのかわからない
* どこで失敗したのかわからない

##中間ファイルを作ろう
エラー時に全作業のやり直しは避けたいところ。
データ加工時に中間ファイルを作っておけば、その中間ファイルから作業をやり直すことができます。
中間ファイル自体をチェックすることでエラーの原因追求もできます。
###ありがちなこと
* 処理に失敗したので一からデータ移行やり直し
* 移行プログラムのうちどこで誤ったのかわからない

##データの互換性を確認しよう
既存のデータを新システムに投入できるようにすることは、
移行プログラムの存在意義である以上できているはずです。
ただし、既存と新システムを並行稼動させるときは、
新データの形式(長さ、文字集合などなど)が既存システムにも適合できるようにしないといけません。
###ありがちなこと
* 旧データより新データのほうが受け入れ可能な文字列長が長いため、既存システムに新データを投入することが出来ない
* ユニーク制約に引っかかる

##データベースのマイグレーション
システム移行ともに、普段なかなかできないDBMSのバージョンアップやソフトウェア自体を変更することが多いはずです。
各DBMSのマニュアルやガイドを参考にして、粛々と行いましょう。
###ありがちなこと
* 暗黙のデフォルト処理にハマる
* マニュアルを読まない

##移行済みデータを全件検証しよう
バグ、仕様誤りにより、投入したデータが想定通りになってないことはよくあります。
検証までがデータ移行です。
###ありがちなこと
* データ項目が空になっている
* 件数がおかしい
* デフォルト値の考慮漏れ（既存、新規、移行プログラム）

##ETLツールやデータフローツールを使ってみよう
上記のような仕組みは、自分たちで実装するより既存のツールを流用したほうがQCDすべて確保できると思います。
クラウドベンダーのツールやOSSのETLツールを検討しましょう
##普通のアプリケーションとなるべく同じようにしよう
使い捨てとは言え、移行プログラムも一つのシステムである以上、普通のシステムと同じ部分で問題が発生します。

* 自動デプロイ
* 集計処理
* ログ確認


手のかからない範囲で自動化しましょう。

###ありがちなこと
* 手作業の誤りで作業やり直し
* デプロイが苦行
* ログ確認が苦行
* テスト、レビューしてない
* 障害フローがない


#移行インフラ編
##専用の環境を手配しよう
データを全件移行することから、移行プログラムは重くなりがちです。
流用や相乗りは避け、プログラムを動かす前に新しい環境を準備しておきましょう。
プログラムが正しく動くか検証を忘れずに。
###ありがちなこと
* CPU、メモリ、ディスク、ネットワーク...サーバーのスペックがなにもかも足りない
* ネットワークがつながらない
* そもそもサーバーがない

##監視しよう
移行プログラムは使い捨てとはいえ、
重い処理なので監視しないと危険です。
どれくらいサーバのリソースを利用するかも含め、
通常のモニタリングと同じぐらいの精度を目標にしたいところ。
移行元データを取得する際は、既存システムに影響がないかも監視しましょう。
###ありがちなこと
* データ移行の負荷で既存システムに影響出まくり
* 移行関係のデータのせいでディスクフルになりサーバ作り直し
* 監視はあるけど通知がないのでずっとグラフを見てないといけない
 
##バックアップを取ろう
サーバ障害や手順ミスにより、移行中のデータが消えてしまう。
そんなことになる前に、バックアップをとりましょう。
特に移行プログラムの作りが甘いときは、運用でカバーすることが多いので危険です。
###ありがちなこと
* 移行元データが吹っ飛んだので移行やり直しができない
* 移行用データが吹っ飛んだ
* 調査用に一時的に作ったファイルが吹っ飛んだ

##セキュリティを確保しよう
データ移行全般において、調査や集計によりデータがあちこちに散らばりがちです。
セキュリティを忘れないようにしましょう。
あまりやりすぎると移行が進まないのでほどほどに。
###ありがちなこと
* 一時ファイルや集計ファイルがPC、共有サーバといったあちこちに散らかっている

#参考にすべき資料
[最後の難関 システム移行](http://itpro.nikkeibp.co.jp/article/COLUMN/20080303/295290/)ぐらいで、
データ移行そのものはあまり情報がありません。
書籍も少ないような気がします。秘伝の技ですね。

DBマイグレーションだけならそれなりに情報がありますが、
技術上解決できる問題なので、そこで詰まることは少ないと思います。

データ移行とは直接関係しませんが、
ビッグデータのETL関係の資料は、
移行プログラム関係の一部のトピックと関連があり、ためになります。

## 関連記事

* [ローンチチェックリスト： 考慮漏れが多そうな部分編 - Qiita](https://qiita.com/yoshi-taka/items/a220a1c5c9314642c185)
* [SELECT権限だけでmysqldumpできることがある - Qiita](https://qiita.com/yoshi-taka/items/3628c5d4240fbff02134)
* [MySQL権限一覧をきれいに作る方法と、rootユーザー以外で棚卸しする方法 - Qiita](https://qiita.com/yoshi-taka/items/94467014ec7e9e3e8ec8)