開発日報

窓際エンジニアの開発備忘。日報は嘘です。

【マイクロサービス】サーガ概説

課題

DBが分散した状態でシステム全体としてデータ整合性どのようにして担保するのか(複数サービスにまたがったトランザクション制御どうやる)?

対策

1. 「2層コミット」を使って担保する

分散データベースに対してデータベース間の整合性を担保する方法。 DB1, 2 にそれぞれコミットOKか問い合わせを行い、共にOKだったらコミットを実施する。

 → 通信が同期になり可用性が下がってしまうのでマイクロサービスで「2層コミット」は使わない

(以下の図は「OK」の部分の矢印が逆でした。DBからアプリに対してOKを返します。)

f:id:yuuu1993g:20211106221744p:plain

2. 「サーガ」を使って担保する

マイクロサービスで2層コミットを使わずにデータ整合性を担保する方法。

複数サービス・APIにまたがった処理の呼び出しやトランザクションを制御する機構。

サーガのトランザクション構成

サーガは3つのフェーズに分けて処理が制御される。

1. 補償可能トランザクション

失敗する可能性があるのでロールバックできる必要があるため、 ロールバック用の処理(補償トランザクション)を別途定義する。

2. ピポットトランザクション

ロールバックするかどうかの境界。

3. 再試行可能トランザクション

必ず成功する。

[Q.]

サービスが複数ある中で処理の順番を担保したり、複数サービスを強調させるのってどうやる?

[A.]

  • コレオグラフィ : 各サービスが必要なイベント(トピック)をサブスクライブする。
  • オーケストレーション : 中央のコーディネーターが各サービスに対して指示をする。複雑なトランザクション制御の場合はこちらを使用する(場合によるロールバックとかの制御もできるし)。

サーガの問題点

複数サービスをまたがったトランザクションにおけるACID属性のうち、独立性に問題が生じる。

Isolation(独立性/隔離性)とは、トランザクション実行中の処理過程が外部から隠蔽され、
他の処理などに影響を与えない性質である。

マイクロサービスでは1連のトランザクションが分断され、サービス毎にコミットされる。そのためタイミング次第ではトランザクションの途中状態が閲覧可能になってしまっている。そのため一部のデータがまだ古い状態で別の処理が走ったりしてデータの不整合が生み出されてしまう。

サーガの対策

「あきらめる」か「楽観ロック」「悲観ロック」に相当する方法を活用する。

あきらめる

業務要件次第ではあり。

値再読み込み(Re-Read Value)

楽観ロックに相当。書き込み時にデータ確認して異なっていればロールバックする。

(例)
予約時にDBから「更新日付」を取得する。
その後、予約を確定する際に「更新日付」が変更されていないか確認し、変更されていなければコミットする。
変更されていたらロールバックする。

セマンティックロック(Semantic Lock)

悲観ロックに相当。セマフォを使って排他制御する。

(例)
DBに「状態」列を作成し、保証可能トランザクションの段階では「PENDING」にしておき、再試行可能トランザクションで「DONE」にする。
トランザクションから更新する際に、「PENDING」を見つけた場合 以下のいずれかの対応になる。

  • 処理を失敗させ、ユーザーに再試行させる
  • 処理が可能になるまで舞つ