/note/tech

DBリファクタリングにおける戦略と実践方法

要約:

■ 1. データベースリファクタリングの必要性

  • 肥大化の問題: サービスの成長に伴いデータベースが肥大化し、パフォーマンス低下やメンテナンスが困難になる
  • 予見の限界: 最初から設計を工夫しても、サービスの成長に伴う要件変化をすべて予見することは難しい
  • AI時代の加速: AIを利用したソフトウェア開発が主流になりつつある昨今、データベースの成長速度はさらに加速している
  • 変わらぬ重要性: AI時代でもデータベースリファクタリングは必要不可欠なスキルである

■ 2. リファクタリングの基本戦略

  • 4つのステップ:
    • あるべき姿を定義する
    • リファクタリングの方針を決める
    • 安全にリファクタリングを行うための仕組みを準備する
    • リファクタリングを実施する
  • あるべき姿の定義: リファクタリングの目的を明確にし、どんな効果を得たいのかを整理してゴールから逆算してステップを決める
  • 優先順位の重要性: 全てを同時にリファクタリングするビッグバンリリースは避け、腐った牛乳とチーズの例のように優先順位をつけて小さく進める

■ 3. リファクタリングの方針策定

  • 段階的アプローチ: データベースリファクタリングはリスクが高いため、一足飛びではなく段階的に進めるステップを決める
  • 削除フラグ廃止の具体例:
    • deleted_userテーブルとactive_userテーブルを作成する
    • userテーブルにINSERTする際に、active_userテーブルにも書き込む
    • delete_flag=trueに更新する際に、deleted_userテーブルに書き込み、active_userから対象を削除する
    • userテーブルから、delete_flag = falseのデータをactive_userテーブルにコピーする
    • userテーブルから、delete_flag = trueのデータをdeleted_userテーブルにコピーする
    • active_userテーブルとdeleted_userテーブルをUNIONし、view_userテーブルを作成する
    • userテーブルへの参照をview_userテーブルに切り替える
    • userテーブルの追加・更新処理をなくす
    • userテーブルをDROPする
  • 達成条件の設定: 次のステップに進むための達成条件やロールバックする場合の条件を決め、失敗時の影響を最小化する
  • スケジュールと根回し: 大まかなスケジュールを作成し、マルチアプリケーションの場合は各チームに根回しを行いリソースをアサインしてもらう

■ 4. 安全な仕組みの準備

  • 3つの重要な仕組み:
    • 自動テスト
    • オブザーバビリティの強化
    • データの整合性チェックの自動化
  • 自動テスト: E2Eテストや単体テストを自動化し、CI/CDで自動実行することで意図しない振る舞いやバグを早期に発見する
  • オブザーバビリティ: モニタリングツール、ログ収集ツール、APMツールを活用し、OpenTelemetryなどの分散トレーシングでテーブルの利用状況を把握する
  • データ整合性チェック: リリース時だけでなく10分に一回など定期的にバッチで実行し、エッジケースでの不整合を早期発見する

■ 5. ダブルライトの実装アプローチ

  • 3つの主要アプローチ:
    • データベースを利用した実装
    • アプリケーションでの実装
    • ミドルウェアを活用した実装
  • トリガーの利用: データベースの機能でアプリケーション側の変更を最小化できるが、運用コストが上がるため期間限定のつなぎとして利用する
  • 生成列の活用: first_nameとlast_nameを連結してfull_nameを自動生成するなど、計算後の列を自動的に設定する方法である
  • アプリケーション優位: アプリケーション側はデータベースより変化に強く、ロールバックが容易でテストもしやすいため推奨される

■ 6. アプリケーション側の実装方法

  • 関数でラップ: データベースアクセス関数をラップしてダブルライトのロジックを実装する最もシンプルでわかりやすい方法である
  • セーブポイントの活用:
    • userテーブルの書き込み成功後にセーブポイントを設定する
    • active_userテーブルへの書き込みが失敗してもサービスを継続できるようにする
    • 失敗をログに残すことで検知できるようにする
  • シャドウページング:
    • 古いuserテーブルとview_userテーブルの両方を参照し比較する
    • 不整合があればログに残すことで早期検知する
    • 今まで通りuserテーブルのデータを返してサービスを継続する
  • フレームワーク利用: ORMのイベントリスナーやTraitで一気にダブルライトを実装できるが、暗黙的な振る舞いになりテストが難しくなる

■ 7. ミドルウェアを活用した方法

  • CDCの活用:
    • AWS DMSやDebeziumなどのツールでデータベースの変更を検知し、別のシステムに伝搬する
    • リファクタリング前後のDBを分離でき、データの安全性を確保できる
    • コンポーネントが増える分、監視対象も増え運用コストが増加する
    • CDC自体が単一障害点になることが多く、厳しいSLAを求められる場合は注意が必要である
    • リファクタリング完遂後は必ずCDCを廃止し、新たな技術的負債にしない
  • 非同期書き込み:
    • メッセージキューを利用して、userテーブルにINSERTした後にキューに書き込む
    • 別のワーカーでactive_userテーブルにINSERTする
    • CDCと違い単一障害点になりにくく、データの前加工も柔軟に実装できる
    • CQRSパターンや参照整合性が緩い場合に有効である
    • データの整合性チェックは必須であり、遅延や失敗時の対応も検討が必要である

■ 8. まとめ

  • 戦略的な準備: 今回紹介した方法を組み合わせて継続的にデータベースリファクタリングを進めることで、効果的に負債を解消できる
  • 事業成長の鍵: クラウドネイティブなアーキテクチャやAIの発達でデータベースの肥大化が加速しているからこそ、継続的なリファクタリングが重要である
  • 最も重要なこと: データベースリファクタリングは影響範囲も広く時間がかかるため、一番必要なのはやり切るという覚悟である