Dev Study
← DNSを運用する側から見る
レッスン 3 / 8·約 9 分·第9期 DNSを運用する側から見る

TTLは上限であって予定ではない — 反映されない本当の理由

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP今ここ
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理
  7. DB保存

第26週で DNS の TTL の単位が秒数だと確認しました。では、その秒数が意味するのは何でしょうか。

まず結論

TTL は「この秒数までは保持してよい」という**上限**であって、保持の義務でも、問い合わせの予定でもありません。RFC 2181 §8 が **"a maximum time to live, not a mandatory time to live"** と明記しています。

だから TTL を過ぎても何も起きないことがあり、短く捨てられることもあります。「まだ古い値が返る」の正体は、期限の切れていない各キャッシュが独立に古い値を持っている状態です。

? 読む前に予測

TTL 300 のレコードをリゾルバ経由で引きました。その300秒後に、このリゾルバは必ず権威へ問い合わせ直すでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

TTL が指定しているのは上限だけ

第26週『パケットを自分の目で見る — 切り分けの型』で、DNS の TTL が秒数だと確認しました。では、その秒数は何を指定しているのでしょうか。RFC 2181 §8 の答えは短いものです。

Implementations are always free to place an upper bound on any TTL received, and treat any larger values as if they were that upper bound. The TTL specifies a maximum time to live, not a mandatory time to live.

maximum time to live であって、mandatory time to live ではない。 TTL は「これ以上は保持するな」という上限で、「これだけ保持しろ」という義務ではありません。実装が自分の上限をかぶせることも認められます。

帰結は2つ。上限より短くなりうること。そして期限が来ても、それ自体は何のきっかけでもないこと。期限切れは「もう使えない」状態で、「取りに行く」動作ではありません。

具体実物

権威は減らない、リゾルバ経由は上下する

以下は macOS 26.5.2 / DiG 9.10.6 / 2026-09-17 JST・日本国内での実測で、再実行すれば違う数字になります。 まず権威へ直接、10秒間隔。

$ dig +noall +answer @<権威サーバ> example.com A — 10秒間隔で3回コマンド出力
--- sample 1 22:41:26 ---
example.com. 300 IN A 172.66.147.243
example.com. 300 IN A 104.20.23.154
--- sample 2 22:41:36 ---
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243
--- sample 3 22:41:46 ---
example.com. 300 IN A 104.20.23.154
example.com. 300 IN A 172.66.147.243

3回とも 300 のままです。権威が返すのは設定そのものなので減りません。並び順だけが入れ替わっています。ヘッダは flags: qr aa rd で aa が立っています。

次に、同じ名前をリゾルバ経由で5〜10秒間隔で8回。

$ dig +noall +answer example.com A の TTL — 5〜10秒間隔で8回(リゾルバ経由)コマンド出力
22:40:34 sample1 TTL=149
22:40:39 sample2 TTL=288
22:40:44 sample3 TTL=21
22:40:54 sample4 TTL=285
22:40:59 sample5 TTL=280
22:41:04 sample6 TTL=119
22:41:09 sample7 TTL=258
22:41:14 sample8 TTL=109

5秒しか経っていないのに、149 から 288 へ跳ね上がります。 その次は 21 まで落ち、10秒後にまた 285 へ戻ります。

壊れているのではありません。公開リゾルバのアドレスの裏に独立したキャッシュを持つ複数のインスタンスがいる、と考えると説明がつきます(作り方の1つが、1つのアドレスを複数地点から広告する anycast。本コース4本目で扱います)。届く先が毎回変わり、キャッシュした時刻も別々なので残り時間はばらつきます。どれに届いたかは測定から見えません。

どの値も 300 以下に収まっている点にも注目を。上限は守られ、その範囲のどこが返るかは当たったインスタンス次第。

✓ ここまでの確認

リゾルバ経由で5〜10秒おきに引いたところ、返る TTL が 149 の次に 288 へ跳ね上がりました。何が起きていますか。

抽象原理

上限値は「その時刻に何かが起きる」と言っていない

TTL は、期限が来たら何かが始まる予定表ではありません。期限切れのキャッシュは「そのままでは使えない」になるだけです。

リゾルバから見れば、DNS は一貫してプルです。期限切れの後に誰も引かなければ、権威への問い合わせは起きません。

実装が課してよい上限にも実物があります。

受け取った TTL をどこで頭打ちにするか(各ドキュメントの既定値)表
実装 設定名 既定値
BIND 9 9.20.29 max-cache-ttl 604800 秒(1週間)
Unbound 1.26.1 cache-max-ttl 86400 秒(1日)

同じ TTL でも、受け取る側の実装が違えば上限が7倍違います。 しかも既定値で、運用側が変えていることもあります。逆方向の設定もあり、Unbound の cache-min-ttl を有効にすると、ドキュメントの言葉で "cached for longer than the domain owner intended" という状態になります。

具体実物

第30週の fail_timeout も、予定ではなく上限だった

同じ形の数値を第30週『死活監視 — 壊れた実体を外す仕組み』で見ています。nginx の fail_timeout の既定は「10秒の間に1回失敗したら、10秒間そのサーバを使わない」でした。

これも、その10秒が経った瞬間に何かが起きるという意味ではありません。次に振り分ける機会で除外から外れるだけで、リクエストが来なければ10秒が経ったことは誰にも観測されません。

✓ ここまでの確認

「TTL を 86400 にしたので、どのリゾルバも丸1日そのレコードを保持する」——この説明の評価はどれですか。

⇄ 2つを見比べる
具体例 A

DNS の TTL(今回)

RFC 2181 §8 は TTL を maximum time to live と定義し、実装が独自の上限を課すことも認めています。取り直しは誰かが引いたときに起こります。

TTL 300 が言っていること / 言っていないこと表
言っている 300秒までは使ってよい
言っていない 300秒は必ず保持される(実装が短く切ってよい)
言っていない 300秒後に問い合わせが行く(引く人が要る)
具体例 B

nginx の fail_timeout(第30週)

既定は「10秒の間に1回失敗したら、10秒間そのサーバを使わない」。この10秒も、経過した時点で復帰処理が走るのではなく、次に振り分ける機会で候補へ戻る境目です。

fail_timeout 10s が言っていること / 言っていないこと表
言っている 10秒のあいだ、このサーバへ振り分けない
言っていない 10秒後に復帰の確認が行われる(要求が要る)
言っていない 10秒後にサーバが直っている(健全性は別)

どちらも秒数ですが、どちらも「その時刻に何かが起きる」とは言っていません。共通するのは何でしょうか。

「その秒数が経った瞬間に、誰が何をするのか」を両方で書き出してください。動くのは時計でしょうか。

抽象原理

図にすると、動く順序が見える

TTL が付いたレコードが、どこで何に変わるか
権威が返す設定値をそのまま返す○ 減らない。aa が立つ
リゾルバが保持TTL を上限として保持○ 実装の上限で切られうる
残り時間が減るそのキャッシュの中だけ○ 別インスタンスなら別の値
期限切れ使えない状態になる× ここでは、まだ何も起きない
誰かが引く問い合わせが来て取り直す○ 引く人がいなければ起きない
↓
動き出すきっかけは時計ではなく、問い合わせ
  • ・減るのはキャッシュの中だけ。権威側の値は変わらない
  • ・「行き渡る」は広がる何かを含意するが、移動しているものは無い

この章のまとめ

  • RFC 2181 §8 は TTL を maximum time to live, not a mandatory time to live と定義する。上限であって義務ではない。同じ節が 実装は独自の上限を課してよいとも明示する。
  • その上限の既定値は BIND 9 9.20.29 が 604800 秒、Unbound 1.26.1 が 86400 秒で7倍違う(版を添えて引く)。
  • 権威サーバの TTL は減らない。 減るのはキャッシュの中だけで、aa の有無が手がかり。
  • 公開リゾルバ経由の TTL は 単調に減らない(実測で 21 の次に 285)。別のキャッシュに当たると考えられ、「反映されたか」の材料にはできない。
  • 「反映されない」の正体は、期限の切れていない各キャッシュが独立に古い値を持っている状態。期限切れは動作のきっかけではなく、DNS はプル。NOTIFY も配信ではない。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

RFC 2181 §8 が TTL について述べている内容として、原文に沿うのはどれですか。

用語集(4語)
TTL の上限性 (RFC 2181 §8)
保持してよい時間の上限であって、義務でも予定でもない。原文は "The TTL specifies a maximum time to live, not a mandatory time to live"。実装が独自の上限を課すことも認められている。
キャッシュ側の TTL 上限設定
受け取った TTL をどこで頭打ちにするかの設定。既定値は BIND 9 9.20.29 の `max-cache-ttl` が 604800 秒、Unbound 1.26.1 の `cache-max-ttl` が 86400 秒。
aa フラグ (Authoritative Answer)
応答が権威サーバ自身のデータから返されたことを示すフラグ。権威へ直接問い合わせた応答には立ち、キャッシュから返った応答には立たない。
NOTIFY (RFC 1996)
ゾーンの変更を権威サーバ間で伝える仕組み。データは運ばず、受け取った側が自分から SOA を問い合わせて転送を始める。