競合検出と解決
1)紛争とみなされるもの
競合とは、2つ以上の変更ソースが同じエンティティ、リソース、または不変量の互換性のない状態を要求する状況です。
Syntactic: 1つのファイル/キーに重複する変更(Gitでのマージ競合、Kustomizeでのパッチ衝突)。
セマンティック:スキームに従って正しい文書は、ビジネス不変(デビット額≠クレジット、上限を超えた)に違反します。
Operational/temporal:レースの書き込み/読み取り、重複イベント、原因-効果の不一致。
ドメイン:資源の競争操作(二重切符の販売、overbookの商品)。
タスク:できるだけ早く競合を検出するには、その原因を説明し、安全にアクションのいずれかを選択します:自動回復、リトレイ、合併、補償、エスカレーション。
2)検出メカニズム
2.1バージョンと状態の比較
ETag/If-Match in REST、 rowversion/xmin in DB-lost update detection。
3-way merge (base、 our、 theirs)-互換性のない編集を強調表示します。
Checksum/Hash by field/document-安価な比較。
2.2時間と因果ラベル
ランポートクロック:合計順序「時間内におおよその」。
2.3不変量と制約
スキームとバリデータ(JSON スキーマ/OpenAPI)-構文的妥当性。
不変量:一意性、非負荷性、バランス、ACLルール。
整合性チェック:FK/UNIQUE/EXCLUDEインデックス、部分拘束。
ドメインはコード/ポリシー(OPA/Kyverno/Conftest)でアサートされます。
2.4イベントストリームでの検出
Idempotency Key/Dedup Store(例:Redis/DB with TTL): takesの拒否。
トランザクション/ストリーミングで正確に1回:トランザクションID、 producer epoch、 consummer-offset。
シーケンスギャップ検出:ギャップ、繰り返し(n、 n+1、 n+1)。
2.5観察可能性および警報
Error/Collision/Retray Prometrics。
3)決議戦略
3.1フルオート(定義によって金庫)
CRDT(競合のない複製データ型):G-Counter、 PN-Counter、 OR-Set、 LWW-Register、 Map/Graph CRDT。
調整なしで収束を確保する。損失/保持意味論の選択は重要です。
可換演算:任意の順序で適用されます(増分、付録)。
Idempotentハンドラ:繰り返しは結果を変更しません(upsert by key、 put-if-absent)。
構造の楽観的なマージ:'deep merge+policy'と決定論的順序。
3.2半自動(ポリシー付き)
3-way merge+array rules ('replace' append 'uniqueBy (key) | patchBy (key)')。
LWW (Last-Write-Wins):単純だが因果正しさが失われるリスク。
ソースの優先順位は「interactive input> config from file> defaults」です。
ビジネスルール:「制限を超えた場合-部分的な確認/補償」。
3.3コーディネート
OCC/MVCC(楽観的ブロッキング/マルチバージョン):バージョン調整、リトレイ。
悲観的なロック:'SELECT……更新のため'、分散ロック(Redlock/DB ロック/etcd)。
コンセンサス(いかだ/Paxos): 1人のリーダーは順序を決定します;競合は少なく、価格はレイテンシです。
3.4パーソンインループ(HITL)
マニュアルマージ/仲裁のためのUI(特にコンテンツ、関税、カタログ)。
diffaのプレビュー、ポリシーの説明、ボタン:「私たち/彼らを受け入れる」、「フィールドをマージ」、「補償を作成する」。
4)建築の層によるパターン
4.1 API/REST/gRPC
楽観的な並行性:'If-Match: <etag>'、競合の場合409/412→クライアントは新鮮なETagを考慮して引き込みます。
POSTのIdempotency-Key(支払/注文)。
セマンティック409:理由と提案された行動を伝える。
4.2データウェアハウス
RDBMS: MVCC(スナップショット分離)、ユニークなインデックス、部分インデックス。
KV/Doc stores: versions/revisions (rev)、 compare-and-swap (CAS)。
マルチマスターレプリケーション:/CRDTを使用するか、重要なエンティティに対してのみリーダーに書き込みます。
4.3キュー/ストリーミング
正確に一度(実質的に-「効果的に一度」):トランザクションプロデューサー+アトミックライトツーシンク。
コンソール上でDedup:最後のN IDを格納する、upsert/mergeロジック。
Outbox/Inboxパターン:一貫したイベントパブリッシング。
4.4構成とIaC
GitOps、 policy-gates (OPA/Kyverno)における3ウェイマージ。
Kustomize/Helm:決定論的マージ戦略と「未知の鍵」の禁止。
Terraform: 「drift vs wanted」紛争信号としてのplan-diff。
5)アルゴリズムと例
5.1 3ウェイマージ(簡略化)
text resolve(base, ours, theirs):
diff1 = delta(base, ours)
diff2 = delta(base, theirs)
if independent(diff1, diff2): return apply(base, diff1 ⊕ diff2)
if conflictsOnlyInArrays: return arrayPolicyMerge(...)
else:
return CONFLICT with hunks
5.2 RESTリソースのOCC
http
Client reads
GET /accounts/42 -> ETag: "v17", body: {balance: 100}
Trying to write off
PUT /accounts/42
If-Match: "v17"
{balance: 50}
If someone has managed before
HTTP/1. 1 412 Precondition Failed
{error: "version_mismatch", currentEtag: "v18"}
クライアントは再読み込みし、現在の状態にデルタを適用して繰り返します。
5.3セマンティック競合(不変)
pseudo on Debit(accountId, amount):
current = read(accountId)
if current. balance - amount < 0:
return REJECT ("insufficient _ funds") # write early detection (accountId, version = current. version+1, balance=current. balance - amount)
5.4 CRDT: OR-Set(スケッチ)
要素は、固有のタグ、削除-特定のタグのために追加されます。
「add vs remove」競合は、removeタグを使用して可視のaddタグのみを削除することで解決されます。
6)決断の方針: 形式化する方法
建築の教義で記述して下さい:1.プライオリティ・チェーン。
2.データ型による戦略:スカラー/オブジェクト/配列/マルチメディア。
3.因果モデル:バージョン、Lamport、ベクトルクロックを使用します。
4.損失意味論:コンセンサスが必要なLWWで失われる可能性のあるもの。
5.時間ウィンドウ:重複除外用のTTL、 idempotencyウィンドウ。
6.エスカレーション:自動解像度が禁止されている場合、UI/承認の要件。
7.補償:不変量を再構成するためのSAGA戦略「キャンセル/補償」。
7)メトリクスとSLO
conflicts_total{type}は型ごとの周波数です。
conflicts_resolved_auto_ratio-自動許可の共有。
mean_time_to_resolutionは決済までの平均時間です。
lost_update_incidents-失われた更新のインシデント。
idempotency_hit_rate-動作したIdempotencyキーの割合。
divergence_depthはレプリカ発散の深さ(バージョンのベクトル)です。
SLOの例: 「構文競合の≥ 99%は≤ 5秒で自動的に解決され、意味競合は≤ 15分でHITLと解決されます。」
8)実用的なシナリオ
8.1支払い方法
キー:Idempotency-Key、 OCC on balance、 SAGA for reversible steps。
競合:二重書き込み→dedup+バランスシートのバージョンチェック→部分補償。
8.2在庫/チケット
オプション:悲観的なスロット/シートブロッキング;TTLの期限切れで楽観的な予約;compare-and-reserveキュー。
8.3コンテンツ/カタログ
3ウェイマージ+HITL: エディタが合計を選択します。「安全」フィールドの自動ルール(価格に影響を与えないSEOタグ)
8.4 GitOps/Kubernetes
アプリケーションの前にレンダリングと検証。未知のキーを拒否します。禁止「--force」レビューなし。
ドリフト検出とポリシー強制ロールバック。
9)アンチパターン
どこでもLWW:因果関係の損失のコストでシンプルさ。
idempotencyのない隠されたリトレイ:雪崩のような重複。
明示的な配列ポリシーがありません-設定ポイントのサイレント損失。
ネットワーク上のグローバルなミューテックス:SPOFと長いロック。
原因監査なしの「ブラインド」補償:繰り返し競合。
10)実装チェックリスト
- ドメインの競合タイプと不変量を定義します。
- バージョン管理メカニズム(ETag/xmin/vector clock)を選択します。
- 重要なPOST/コマンドでidempotencyを有効にします。
- データ型(スカラー/配列/オブジェクト)でマージポリシーを設定します。
- スキーマバリデータとプリコミットドメインチェックを有効にします。
- 衝突とアラートメトリックを設定します。
- 重要なエンティティ-リーダー/コンセンサス、またはCRDT。
- HITLフローとUX(差分、コメント、監査ログ)をワークアウトします。
- SLOと補償手続き(SAGA)を文書化する。
11) FAQ
Q:いつCRDTを選ぶべきか、いつコンセンサスを選ぶべきか?
A: CRDTは、最終的な一貫性が許容され、高可用性/ローカルエントリが重要な場合に適しています。コンセンサス-厳格な不変量と厳格な操作順序(現金残高、アクセス権)を持つデータ。
Q: LWWは十分ですか?
A:キャッシュ、メトリック、セカンダリインデックスの場合-多くの場合はい。ユーザーデータとお金のために、ほとんど常にそうではありません。
Q:重複除外ウィンドウを選択するにはどうすればよいですか?
A:期待される最大再配達の遅れ+ネットワークのジッタに焦点を合わせて下さい、3-5 ×項目99のマージンを加えて下さい。
Q:常にHITLをするべきですか?
A:いいえ。紛争/価値の競合を自動化し、残りをログに記録するためにHITLを残します。
12)合計
効果的な競合検出と解決は、バージョン管理、因果ラベル、不変量、および適切なアルゴリズム(CRDT/OT/OCC/MVCC/コンセンサス)によって補完される明確なポリシーと観測可能性の組み合わせです。競合が「正常な」状況であるシステムは、アクセス可能で予測可能なままです。競合が「例外」であるシステムは、可能な限り最悪のタイミングで破壊されます。モデルを選択し、ルールを形式化し、結果を測定します。