
デプロイ・・・それは、開発担当者が緊張する瞬間でもあり、開発してきた作業が報われる瞬間でもある。
大きなWEBシステムを構築した時、システムの環境は、単にサーバーを1つ用意して、
ローカルから、FTPでアップロードしてサービス公開していたのは、平成初期ぐらいの話です。
最近では、ほとんどの場合が、Githubアクションを使って
オートデプロイしたり、
LINTツールなどを使って自動検証することで、できる限りの事故を無くすのは、最近のトレンドです。
そして、アクセスの多いWebサービスになると、アクセスされるフロントサーバーも、
バランシングして、複数台のサーバーを設けるケースも手軽にできてしまうようになりました。
今回は、ここ数ヶ月間ずっと開発してきたサービスが先月ようやく公開して、
開発サーバーやら、ステージング環境やらを準備して、環境を整え始めた時の話です。
データベースもdevelop用を用意して、本番にデプロイするのが良いという事を開発内で話し合い、仕様が決まりました。
そして、刺繍的な仕様で、実際にどういう風にデータベースのデプロイをするのが良いかを考えた思考内容をブログに残しておきたいと思います。
これからデータベースのデプロイを構築する人に読んで参考にしてもらえると幸いです。
データベースのデータの流れと運用の仕様
今開発したシステムは、データテーブルもモリモリでたくさんあり、
かなり入り組んでいる構造になっているため、同時にデータ更新する対象が全部で11個もありました。
そもそも、データベースのテーブルは、マスター系テーブルと、ログ系テーブルの2種類あり、
マスター系テーブルというのは、リレーションカラムの参照先になるテーブルで、
何度も書き換えなどが行われたり、システムの運用に応じて更新されるテーブルです。
ログ系テーブルというのは、アクセスログのようなテーブルで、
履歴データや、課金データなどの様に、書き換えされずに、追記だけされるづけるテーブルです。
でも、実はこれは単純構造なシステムの話で実際は、マスター系+ログ系テーブルというのもあり、
ユーザーテーブルのように、追記型だけど、その後ユーザー名を変更したり、削除(論理削除含む)をするというテーブルもあるんですね。
ただ、ログ系や、マスター系+ログ系のテーブルは、本番だけでしっかりと動いていれば、さほど問題はなく、
開発環境のデータには、テストデータが入っていれば十分なんです。
重要なのは、マスター系のテーブルで、これらをしっかりと開発用データベースで更新して、本番にデータ・デプロイするのが今回の目的です。
ちなみに、今回対象となるテーブル数は11個ありました。
データベース差分の話
プログラムコードは、Githubで管理してデプロイでき、バージョン管理から、何か問題があった場合のロールバック(巻き戻し)も手軽に行えます。
データベースの場合は、ツールを使ってデプロイする場合もありますが、独自に開発したデータベースであれば、独自の仕様が存在するため、
おいそれとツールの機能をそのまま使うわけにはいかない場合が多いのが現状です。
今回は、マスター系データベースの差分を見つけて、差分に対して処理を行うという処理を実施することにしました。
データベース・デプロイ用のツールも自作するため以下尿な手順を設計してみました。
1. データベース(本番)とデータベース(開発)の特定テーブルの差分を取得
2. 差分に対して開発データベースから本番データベースに対してデータを更新
シンプルに思える作業ですが、データ差分はレコード単位で行い、以下の種類があります。
- insert : 開発側に新たに追加されて、本番側にないデータレコード
- delete : 開発側に存在しなくて(削除されて)、本番側に存在するデータレコード
- update(old) : レコードのupdate timeが、本番よりも、開発のレコードが古い場合
- update(new) : レコードのupdate timeが、本番よりも、開発のレコードが新しい場合
これらの処理で、update(old)は、本来存在している場合は、マスター登録が本番で直接行われた場合で、
今回の場合は、ありえない操作ということで、これは差分検索はするけど、上書きしてしまうと先祖返りしてしまうため、デプロイ対象外とするようにしました。
(逆に、本番->開発の逆輸入をする必要がありますが、運用的にありえなそうなので、今回は操作しないようにしておきます)
ツール構築のポイント
実際の開発ポイントですが、大前提としてのデータベース設計と、必要になるツールの細かなロジックをリストアップしてみました。
1. データベースのテーブル全てに、create,updateカラムは必須
今回の差分チェックをするために、データベースの全てのテーブルには、レコード登録日時と、更新日時を付与してある必要があります。
これがないと、書き込みタイミングの新旧差分が出せないからですね。逆にいうと、このデータがあるだけで、簡単に差分が出せるということです。
あと、重要なのは、できるだけテーブルのユニークID(インクリメントされるのがベスト)です、これがないとちょっとしんどくなるかも。
2. レコード差分検出コード
本番、開発、共に同じテーブル構成であることが前提として、
レコード差分の検出は、基本的に、IDのある無しと、update日時の違いうものを取得することで、差分レコード一覧が抽出されます。
今回は、全てPHPで処理しています。断片的なコードですが、以下の手順で差分が検出できます。
まずは、2つのテーブルのidとupdate_atの値のみを取得(これに絞ることで、かなり処理するサーバーのメモリ値を削減できます)
SELECT id,update_at FROM テーブル名
これで、開発側、本番側の一覧を取得しておきます。
次に2つのデータを比較して、insert,delete,update(old,new)を振り分けます。
private function get_diff_lists($data_1=null, $data_2=null){
$a = array_column($data_1, 'update_at', 'id');
$b = array_column($data_2, 'update_at', 'id');
$insert = [];
$update_old = [];
$update_new = [];
$delete = [];
// A devサーバー / B 本番サーバー とする
foreach($a as $id => $timeA){
// Bに無い → AからINSERT
if(!isset($b[$id])){
$insert[] = $id;
}
// Bが古い → AからUPDATE
else if($timeA > $b[$id]){
$update_old[] = $id;
}
// Bが新しい → 何もしない
else if($timeA < $b[$id]){
$update_new[] = $id;
}
}
foreach($b as $id => $timeB){
// Aに無い → Bから削除
if(!isset($a[$id])){
$delete[] = $id;
}
}
return [
"insert" => $insert,
"update_old" => $update_old,
"update_new" => $update_new,
"delete" => $delete,
];
}
これで、それぞれの違い属性別に、テーブルのidだけが取得できたので、次のコードで、レコードを取得します。
$list_array = implode(',',$diff_list);
SELECT *
FROM テーブル名
WHERE id IN ({$list_array})
ちなみに、実際のレコード取得は、insert、delete、update(old,new)それぞれ行う様にしましょう。(1つのSQLクエリでもかけますけど)
3. カラム構造の差分チェックも必要
上記とは違いますが、2つのテーブルのそれぞれのカラムに差異がないかもチェックしましょう。
上記のレコード取得をした際に、1つ目のレコードのkeysを比べるだけでも良いかと思います。
あとがき
データベースの差分をチェックするところまで、今回は説明しましたが、
その後は、取得したデータを、管理画面システムに反映させて、
・差分の有無
・どの部分のデータが更新されているかの可視化
・テーブル構成の差異がないかのチェック
これらの表示を目で確認した上で、差分同期処理を実行するというだけのシステム構築でした。
実際の差分同期実行は、取得した差分のID一覧を元に、テーブル(開発)から、テーブル(本番)にデータをinsertまたは、update(必要があればdelete)してあげるだけですが、
これはこれでまあまあ、緊張する処理なんですよね。
0 件のコメント:
コメントを投稿