/note/tech

複数集約を跨ぐ処理を1つのDBトランザクションで括る前に読む記事

要約:

■ 1. 問題提起: 複数集約を単一DBトランザクションに束ねることへの警告

  • 注文確定処理において在庫集約と注文集約を同一トランザクションで更新するパターンが示される
  • 複数集約を常にアトミックに更新する必要性を感じる場合、それは集約の境界設計を見直すべきシグナルである
  • 集約とは整合性境界そのものであり、常に同一トランザクションで更新が必要な複数集約は、本来1つの集約として再設計すべき可能性がある
  • この考え方はヴォーン・ヴァーノン『実践ドメイン駆動設計』やクリス・リチャードソン『マイクロサービスパターン』等の既存文献で既に整理されている

■ 2. 強整合の境界と弱整合の境界

  • 整合性の境界は二層に区別される:
    • 集約の境界(強整合): 内側の不変条件をアトミックに維持する
    • ユースケースの境界(弱整合): 複数集約に跨がり、即時性や不可分性を求めない
  • 複数集約を跨ぐユースケースは弱整合の境界として扱うべきであり、ユースケースの都合を強整合の境界にしてはならない

■ 3. 単一DBトランザクションに束ねるコストとリスク

  • History list lengthの問題:
    • 長いトランザクションによりMySQL/InnoDBで古い行バージョンの後始末が遅延する
    • 読み書きの遅延、パージ処理の遅れ、Upgrade・Recoveryの複雑化が生じる
  • ロック獲得順序と循環デッドロック:
    • 複数トランザクションが異なる順序でロックを獲得すると循環デッドロックが発生する
    • ロック獲得順序はドメインモデルから導かれない永続化層由来の暗黙的制約である
    • 低負荷環境では顕在化せず、本番ピーク時に初めてエラーが頻発する
    • 楽観ロックを用いてもversion不一致による失敗とロック競合の両方が発生しうる
  • 読み取り側への暗黙的依存:
    • 複数集約の同時更新前提はクエリ設計にも組み込まれる
    • 後から更新手順を変更する際、読み取り側も見直しが必要となり変更コストが増大する

■ 4. アクターモデルによる解決: 1集約1アクター

  • CQRS/ES環境でアクターモデルを採用する場合、1集約が1アクターに対応する
  • 強整合の境界が構造的に強制されるため、複数集約を跨ぐアトミック更新の経路が通常のコマンド処理に置かれない
  • DB由来の循環デッドロックが構造上発生しないという利点がある

■ 5. プロセスマネージャーによる弱整合設計

  • 設計方針:
    • 複数集約を跨ぐユースケースはプロセスマネージャー(オーケストレーション型のサーガ)で調停する
    • 各ステップを個別の集約更新として実行し、失敗時は補償アクションで取り消す
  • ACDとしての捉え方:
    • Atomicity: 補償アクションにより業務上の取り消し済み状態へ収束する
    • Consistency: 最終的にドメイン状態の整合を満たす
    • Durability: 各ステップのプロセス状態を永続化する
    • Isolation(欠如): 途中状態が外部から見える可能性がある
  • 設計対象となる項目: 補償処理、冪等性、再試行、タイムアウト、重複要求の吸収
  • 読み取りモデルでの中間状態の制御:
    • 中間状態を「payment_pending」や「compensating」等のドメイン語彙としてモデル化する
    • 通常一覧には確定済みの注文のみを表示し、中間状態は処理中ビューや管理者向けビューで表示する