リース・TTL・グレースフルな期限切れ
リースを時間制限付き権限と捉え直すと、分散ロックやリーダーシップが安全になる。クロックスキューへの安全マージン、更新失敗時のフェイルセーフ、グレースフルな期限切れの設計原理が掴めます。
- 1.リースは「いつまで」を区切った時間制限付き権限。サーバー側がその期限を握ることで、応答できなくなった保持者の権限を自動的に取り消し、分散ロックやリーダーシップの基盤になる。
- 2.クロックスキューがあると保持者と発行者で「失効した瞬間」がずれる。だから保持者は実測の有効期間より早めに権限を手放す安全マージンを取り、発行者はマージンぶん長めに保持する。両者の余裕は別物。
- 3.ハートビート更新が失敗したら、保持者は失効が確定する前に自発的に活動を止める(フェイルセーフ)。猶予期間は権限を一斉に剥奪せず、進行中の処理を安全に畳むための時間であり、フェンシングと併用して初めて正しい。
リースとは「時間で区切った権限」である
分散システムで「このノードがリーダーだ」「このプロセスがロックを持っている」と決めるとき、最大の難問は権限を持つノードが応答しなくなった場合にどう回収するかです。明示的に「返却します」というメッセージを待っていては、クラッシュしたノードの権限は永遠に回収できません。
ここで使うのが**リース(lease)**です。リースとは、有効期限付きで貸し出される権限——「あなたは時刻 T までリーダー(あるいはロック保持者)である」という、時間で区切られた約束です。期限が来れば権限は自動的に失効し、保持者が生きていようと死んでいようと、発行者は何も問い合わせずに権限を回収できます。これがリースの本質的な発明です。回収を保持者の協力に依存させず、時間の経過という誰にも止められない事象に委ねる。
リースは分散ロック・リーダー選出・キャッシュの所有権・ファイルロックなど、あらゆる「一時的な占有」の基盤です。TTL(Time To Live)付きロックも、リーダー選出における任期も、突き詰めればすべてリースの一形態です。本記事は、リースがなぜ安全な権限回収を可能にするのか、クロックスキューがどこで効くのか、そして更新失敗時のフェイルセーフと猶予期間をどう設計するかを原理から解きほぐします。
TTL付きの分散ロックは「リースされた排他権」、リーダー選出の任期は「リースされたリーダー権限」です。本記事のリースの議論は、分散ロックの正しさとフェンシングで扱うロックとリーダー選出とスプリットブレインで扱う任期の、どちらにもそのまま当てはまります。共通する原理は「権限に賞味期限を付け、その満了で自動回収する」一点です。
なぜ期限が安全性を生むのか
リースが解決するのは、分散システムの根本問題——「死んだノード」と「ただ遅いノード」を区別できない——への現実的な回答です。非同期ネットワークでは、応答が来ないのがクラッシュなのか、ネットワーク分断なのか、長いGCポーズなのかを、外から確実に判定する方法はありません。
リースはこの区別を諦めることで安全になります。「死んだかどうか」を判定する代わりに、「期限内に更新(renew)してこなければ、その理由が何であれ権限は失効する」と決める。生きているが遅いノードも、死んだノードも、期限までに更新できなければ等しく権限を失う。判定ではなく時間で割り切るのです。
リースのライフサイクル:
付与 : 発行者が「時刻 T まで有効」として権限を貸す
更新 : 保持者が期限前にハートビートを送り、Tを先送りする
失効 : 更新が来ないまま T を過ぎると、権限は自動的に消滅
回収 : 発行者は問い合わせ不要で、T 経過後に権限を再付与できる
ここで決定的に重要なのは、有効期限を発行者(リースを貸す側)が握ることです。保持者が「自分はまだ有効だ」と主張しても、発行者の認識する期限を過ぎていれば、その主張には効力がありません。権限の真実は保持者の自己申告ではなく、発行者の時計が決める。この非対称性が、応答しない保持者を安全に切り離す力の源です。
クロックスキューという落とし穴
リースは時間に依存します。ところが分散システムには統一された時計が存在しません。各ノードの物理時計は、NTPで同期しても完全には一致せず、**クロックスキュー(clock skew、ノード間の時計のずれ)とクロックドリフト(drift、時計の進む速さのずれ)**が必ず残ります。これがリースの正しさを脅かします。
問題は「失効した瞬間」が観測者によってずれることです。発行者の時計で時刻 T に失効するリースを、保持者の時計が遅れていれば「まだ T に達していない、有効だ」と誤認します。逆もまた然り。保持者がまだ有効だと信じている瞬間に、発行者はもう失効と見なして次の保持者へ権限を渡している——この重なりが、二重リーダー・二重書き込みという破滅を生みます。
クロックスキューの害を減らす第一歩は、壁時計(wall clock)の絶対時刻ではなく、単調増加するタイマー(monotonic clock)の経過時間でリースを測ることです。「あと何秒有効か」を各ノードがローカルの単調時計で測れば、ノード間の絶対時刻のずれそのものは無関係になり、残るのは**ドリフト(時計の進む速さの差)**だけになります。壁時計はNTP補正やうるう秒で飛ぶことがあり、リースの判定に使うと突然失効・突然延命が起きます。リース計算には必ず単調時計を使うのが鉄則です。
それでもドリフトは残ります。そこで必要になるのが安全マージンです。重要なのは、保持者と発行者でマージンの向きが逆だという点です。
| 立場 | 誰が早めるか/遅らせるか | なぜ |
|---|---|---|
| 保持者(権限を持つ側) | 実際の期限より早めに権限を手放す | 自分の時計が発行者より遅れている最悪を想定。発行者が失効と見なす前に、自発的に活動を止めれば二重保持を避けられる |
| 発行者(リースを貸す側) | 実際の期限よりマージンぶん長く保持を待つ | 保持者の時計が進んでいる最悪を想定。早く回収しすぎると、まだ有効だと信じる保持者と次の保持者が衝突する |
| 結果 | 失効の前後に「誰も権限を持たない安全な空白」が生まれる | 保持者が早く降り、発行者が遅く渡すことで、両者のアクティブ期間が重ならない |
この両側からマージンを取る設計が肝です。保持者は「リース時間 - マージン」が経過したら、たとえ自分の時計上はまだ余裕があっても権限を手放す。発行者は「リース時間 + マージン」が経過するまで再付与を待つ。マージンは想定される最大ドリフトより大きく取る必要があります。リース時間を T、最大ドリフト率を d とすると、T の間に蓄積しうる時計の食い違いは概ね d × T です。リースを長くするほど絶対的なマージンが膨らみ、有効に使える時間が削られます。これがリース時間設計の根本トレードオフです。
ハートビート更新と更新失敗時のフェイルセーフ
リース保持者は、期限が来る前にハートビート(heartbeat)で更新し、期限を先送りし続けます。問題は更新に失敗したときに何が起きるかです。ネットワークが詰まった、発行者が一時的に応答しない、あるいは保持者自身が遅延した——どの理由でも、更新が期限内に届かなければリースは失効へ向かいます。
ここでの正しい設計原則は、保持者は「失効が確定する前」に自発的に活動を止めることです。これをフェイルセーフと呼びます。素朴な実装は「更新が成功している限り権限を行使し続ける」ですが、これは危険です。なぜなら更新リクエストを送って応答を待っている間にも、発行者側ではすでに期限が過ぎているかもしれないからです。
危険な実装(失効に気づかず権限を行使し続ける):
t0: リース有効(発行者の期限 = t0+10)
t8: 保持者が更新リクエスト送信。だが応答が遅延
t10: 発行者の時計で期限切れ → 次の保持者へ権限を付与
t11: 元の保持者にようやく「更新失敗」が返る
→ t10〜t11 の間、二人が同時に権限を持っていた
安全な実装(フェイルセーフ):
保持者は「自分のローカル期限 - 安全マージン」を過ぎたら、
更新の成否を待たず、即座に権限の行使を停止する。
更新が成功して新しい期限を受け取れたときだけ、活動を再開する。
要点は、「更新が失敗した」と確認できるのを待つのではなく、「更新が成功したと確認できない」時点で止まることです。沈黙はネットワーク上では失敗と区別できません。安全側に倒すなら、確証のない権限は行使しない。これはサーキットブレーカとバルクヘッドで論じる「不確実な依存先を早めに切り離す」発想と同根です。
リース保持者にとって最も危険な瞬間は、ハートビートを送ってから応答が返るまでの待ち時間です。この間、保持者は「たぶんまだ有効」と思い込みがちですが、発行者側ではすでに失効しているかもしれない。GCポーズやスワップで保持者自身が数秒固まれば、その間に蓄積された遅延がマージンを食い潰します。正しい保持者は、ローカルの単調時計で「安全に行使できる期限」を常に計算し、それを過ぎたら更新応答を待たずに即停止する。停止のコストは一時的な可用性低下ですが、二重権限のコストはデータ破壊です。どちらを選ぶべきかは明らかです。
グレースフルな期限切れと猶予期間
リースが失効するとき、権限を瞬時に一斉剥奪するのは乱暴です。失効の瞬間に処理の途中だったリクエストはどうなるのか、進行中のトランザクションは、開いていた接続は——これらを安全に畳む時間が要ります。これが**グレースフルな期限切れ(graceful expiry)であり、そのための猶予期間(grace period)**です。
ただし猶予期間の意味を誤解してはいけません。猶予期間は「失効後も権限を行使してよい延長戦」ではありません。それは単に有効期限を伸ばすのと同じで、安全性を一切改善しません。猶予期間の正しい意味は、**「もう新しい作業は始めないが、進行中の作業を安全に完了・中断させ、状態を引き継ぎ可能にするための撤収時間」**です。
グレースフルな期限切れのフェーズ:
通常期 : 権限を完全に行使。新規受付も処理継続も可
失効が近い : 更新を試みつつ、失敗が続けば撤収準備に入る
猶予期間 : 新規の権限行使は停止。進行中の処理だけを安全に畳む
(フラッシュ、コミット or ロールバック、状態の引き継ぎ)
完全失効 : すべての権限を放棄。次の保持者が安全に引き継げる状態
この設計はグレースフルシャットダウンとドレイニングと同型です。シャットダウン時に新規接続を止めつつ既存接続をドレインするのと同様、リース失効時も新規の権限行使を止めつつ進行中の処理をドレインする。猶予期間は新規を止める時点と、完全に手放す時点の間にあります。
ハートビート間隔・リース時間・猶予期間には設計上の順序関係があります。ハートビート間隔はリース時間より十分短く——一度や二度の更新失敗(パケットロスや一時的な詰まり)ではリースが失効しないよう、リース時間内に複数回の更新機会を確保します。一方猶予期間はリース時間より十分短く——撤収時間が長すぎると、次の保持者がいつまでも引き継げず可用性が落ちます。目安として、リース時間がハートビート間隔の3倍以上、猶予期間がリース時間より短い、という階層を保つと、瞬間的な障害で誤失効せず、かつ本当の障害時には速やかに権限が移ります。
フェンシングなしの猶予期間は危険
ここまでの設計には、まだ穴があります。保持者が約束どおりに自発停止してくれる保証はないという穴です。GCポーズで固まった保持者は、フェイルセーフのチェックすら実行できません。固まっている間に発行者が次の保持者へ権限を渡し、その後ポーズから復帰した旧保持者が——フェイルセーフを実行する前に——一発だけ書き込んでしまう、という競合は理論上残ります。
だからリースはフェンシングトークンと必ず併用しなければ、正しさを完全には保証できません。リース付与のたびに単調増加する番号(エポック)を添え、保護リソース側が過去最大より小さい番号の操作を拒否する。こうすれば、失効に気づかず復帰した旧保持者の遅延書き込みも、書き込みを受ける側で機械的に弾かれます。リースが「権限の自動回収」を、フェンシングが「失効に気づかない暴走の遮断」を担い、二層で初めて安全になります(詳細は分散ロックの正しさとフェンシングを参照)。
リースの本質は「時間で区切った権限」で、失効判定を発行者の時計が握ることで応答しない保持者を自動回収できる、と即答できること。クロックスキュー対策では、絶対時刻でなく単調時計の経過時間で測ること、そして保持者は早めに手放し発行者は遅めに回収するというマージンの向きの違いが頻出。フェイルセーフの核心は「更新失敗の確認を待つ」のではなく「更新成功の確認がない時点で止まる」こと。猶予期間は権限の延長ではなく撤収時間であること。そしてリース単体では正しさを保証できず、フェンシングトークンとの併用が必須、という結論を押さえておくこと。
まとめ
- リースは有効期限付きで貸し出される権限。回収を保持者の協力に頼らず時間の経過に委ねることで、応答しない保持者の権限を発行者が問い合わせなしに自動回収できる。分散ロック・リーダー選出・所有権管理の共通基盤。
- リースは「死んだか遅いか」の判定を諦め、「期限内に更新できなければ理由を問わず失効」と割り切ることで安全になる。有効期限の真実は保持者の自己申告でなく発行者の時計が決める。
- クロックスキュー対策は、絶対時刻でなく単調時計の経過時間で測ること。安全マージンは保持者が早めに手放し、発行者が遅めに回収する——両者で向きが逆。マージンは想定最大ドリフトより大きく取り、リースを長くするほどマージンが有効時間を削る。
- フェイルセーフの核心は、更新失敗の確認を待つのでなく、更新成功の確認がない時点で権限の行使を止めること。沈黙は失敗と区別できないので安全側に倒す。
- グレースフルな期限切れの猶予期間は権限の延長ではなく、新規を止めて進行中を安全に畳む撤収時間。ハートビート間隔 < リース時間、猶予期間 < リース時間の階層を保つ。
- リース単体では、固まった保持者の遅延書き込みを防げない。フェンシングトークンと併用し、二層で初めて正しさが完成する。
DevOps/インフラ Article
リース・TTL・グレースフルな期限切れを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
リース
比較で見る軸
難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 6
導入後に効く点
クロックスキューがあると保持者と発行者で「失効した瞬間」がずれる。だから保持者は実測の有効期間より早めに権限を手放す安全マージンを取り、発行者はマージンぶん長めに保持する。両者の余裕は別物。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- DevOps/インフラ
- タグ数
- 6
判断チェックリスト
- 自社の用途が「リース / TTL」に近いか確認する。
- 強みである「リースは「いつまで」を区切った時間制限付き権限。サーバー側がその期限を握ることで、応答できなくなった保持者の権限を自動的に取り消し、分散ロックやリーダーシップの基盤になる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。