🔲

Webシステムでデータストアの構造を変えやすい設計はないのか?探った件

に公開

イベントソーシングパターンが使えればよいが

https://learn.microsoft.com/ja-jp/azure/architecture/patterns/event-sourcing

イベントソーシングパターン(以後ESと略記する)を使うと、全ての操作履歴を持ってそこから現在の状況をviewのようにテーブルに反映するスタイルとなる。

そのため、やろうと思えばテーブル構造を2つ用意することも可能となる。

これなら移行は簡単となって良いのだが、途中からESに変更するのは大変すぎる。
(また、そうでなくても今までなかった運用とかになるので色々と学習コストや運用コストは出てくる)

この記事は何か他に手はないかな?と考えた記事となる。

メンテに入れるパターン(従来の方法)

ゼロダウンタイムを求められることも多くなっておりメンテ入れるのも難しくなってきているが、メンテが可能である現場では現役の手法だと思う。

これの欠点は大規模に既存のテーブル構造を変えると切り戻しができないか、非常に難しくなること。

また、深夜にメンテすることが多く昼夜逆転するのが好ましくないところでもある。
(月曜日に深夜メンテすると、その週は低パフォーマンスになると同僚がぼやいていたのを思い出す)

Martin Fowler考案のParallelChangeという手法がよいのでは?

手順とか後述するがざっくりいうと拡張(expand)、移行(migrate)、収縮(contract)の手順でいくものらしい。

ざっくり処理の流れ

二重書き開始→バックフィル→突合・修復→制約強化→最終突合→二重書き停止→旧処理削除

前提条件

前提として新・旧の画面は併存させる。
これで利用者側は新がエラーとなっても旧で動かせるので業務が止まることはない。
(画面は変えないでテーブル構造だけ変えるなら不要)

新・旧両方のテーブル構造に書き込みにいく。
(二重書きする)

切り替え手順

  1. tableB作成(並走時に必要であれば制約は緩く開始)
  2. 新機能は表示しない状態でデプロイ
  3. 既存更新処理で二重書き開始(データが無いupdate, deleteは0件になるがエラーにはしない処理にする)
  4. tableAのデータをtableBに移行するスクリプト開始
  5. 1回目データ不整合チェックとリペア処理するスクリプト開始
  6. 新機能を表示する状態にする(新機能でも二重書きする)
  7. しばらく並走する
  8. 2回目データ不整合チェックとリペア処理するスクリプト開始(何もなければ外してよいと判断)
  9. テーブル制約やupdate, deleteが0件でもOKとしてたのをNGにする(並走時の緩さを排除する)
  10. 最終チェックでデータ不整合チェックとリペア処理するスクリプト開始(何もなければ外してよいと判断)
  11. しばらく並走する
  12. 旧処理を非表示にする(利用者が旧処理を使えなくする)
  13. 旧処理を削除

勘所

  • 先に並走を開始するのでUPDATEやDELETEなどが当初0件になるのに対応して並走できる更新処理にすること
  • 裏で空のテーブルから最新に同期が取れるようにする
  • 最後にデータ不整合をチェックしたりリペアするスクリプトなりを用意をする

欠点

  • 両方のテーブルに書き込みに行くので、新処理と旧処理の双方が二重書きする必要がある
    • 書き込みヘビーな場合はいけるのか?
  • 1回のデプロイでは終わらず整合性チェックスクリプトなども必要で手間が掛かる

さいごに

手間はかかるが、かなり安全にデータ構造が移行できる良いやり方だと思う。

切り戻しも簡単で石橋叩いて渡りたい系システムにもとても良いと思う。

実際にやってみてはいないのでやってみたいなと思った次第。

Discussion