要点: 分散ロックだけでは、停止や通信断の後もプロセスが所有権を持つと証明できません。
この記事の用語: Lease:期限付きの所有権。Fencing Token:古い担当者の書き込みを拒否する単調増加番号。
現場の課題
プロセスがLeaseの期限を超えて停止し、別プロセスが所有権を得た後に古い処理が再開することがあります。書き込み先自身が古い所有権を拒否しなければなりません。
単純な対策だけでは不十分な理由
GC停止や通信断がLeaseより長いと、古いプロセスが権限喪失を知らず再開します。Fencing Tokenを資源側で比較し、古い書き込みを拒否します。
処理フロー
Lease要求→Coordinator
Fencing Token→ワーカー
有限Work→Resource
古いトークン拒否
アーキテクチャ上の判断
所有責任 パーティション
Shardをワーカーへ割当てLockを減らします。
Monotonic Fencing
Storageで最終トークンと比較します。
Critical Sectionを有限化
Leaseより短い期限を使います。
さらに深く考える
TTLは所有責任ではない
Storage トークンが実行中コードを拒否します。
Product ConflictをLockで隠さない
共同編集にはバージョンとConflict UXを使います。
実装手順
- まずパーティション分割や冪等性で、共有所有責任そのものを減らします。
- 期限付きLeaseと、取得ごとに増加するFencing Tokenを発行します。
- 書き込み先で、最後に受け取った値より小さいトークンを必ず拒否します。
コード例: Fenced Update
lease = coordinator.acquire(resourceId, ttl = 10s)
result = compute(deadline = lease.expiresAt - 2s)
UPDATE resource
SET value = :result, fence = :token
WHERE id = :id AND fence < :tokenCoordinator Lockだけでは停止した旧担当者の再開を防げません。
想定しておく障害
- 一時停止がLeaseを超えます。
- Coordinator Quorumが失われます。
- 外部呼び出しがLease移動後に完了します。
監視すべきこと
| 指標 | 何が分かるか |
|---|---|
| Acquire・Renew 失敗 | 競合を示します。 |
| Stale トークン Reject | 旧担当者の封じ込めを示します。 |
| Critical Duration | Lease仮定違反を検出します。 |
設計の検証方法
- HolderをTTL超過一時停止します。
- Coordinatorだけパーティションします。
- 増加トークンだけCommitするか試験します。
本番導入の進め方
まず冪等性や楽観Lockを試し、本当に単一担当者が必要な処理だけへFencingを入れます。障害時に使える安全な直列処理経路も残します。
本番前チェックリスト
- Clock仮定を最小化します。
- Renew失敗時は新Workを止めます。
- 長OperationをCheckpoint化します。
まとめ
分散ロックは処理を調整しますが、担当者変更後の正しさを守るのは書き込み先のFencingです。
