nginx の名前解決について「えっ」という挙動があったのでメモ。
なお、ググると結構類似記事が出ていたので知っている人は知っているのかもしれません
nginx は DNS レコードを TTL を無視し再起動(restart)もしくは設定更新(configuration realod)までキャッシュする
以下の nginx 公式ブログにも記載があります。
Using DNS for Service Discovery with NGINX and NGINX Plus
NGINX caches the DNS records until the next restart or configuration reload, ignoring the records’ TTL values.
これはどういう時に問題になるかというと nginx から appliication server に接続を行う設定で、ホスト名でアクセスするような場合に問題が発生する可能性があります。
もう少し具体例を記載します。
- nginx から application server へ example.com というホスト名で接続する
- example.com で名前解決をすると複数の Priavte IP が返却される(例えば複数のサーバーで冗長構成されている)
- この状態で一つのサーバーが何らかの原因で応答不能となる
- 上記により example.com で名前解決をした時の PrivateIP から応答不能になったサーバーがなくなる(A レコードが削除される)
- nginx は最初に名前解決をした結果をキャッシュする為、接続できない PrivateIP に接続してしまうが、当然応答が得られない
上記のようなシナリオが考えられます。
TTL がせっかくあるのでこれを見て欲しいのですが、nginx は見てくれない。。。
どうするのか
上記ブログにいくつか方法が書いてあります。
自分の場合、proxy_pass
を使っていたので resolver
および set
ディレクティブを利用する方法で上記例のような場合でも継続して接続ができる事が確認出来ました。
この場合、TTL が切れると名前解決するようです。
ブログより抜粋
When you use a variable to specify the domain name in the proxy_pass directive, NGINX re‑resolves the domain name when its TTL expires. You must include the resolver directive to explicitly specify the name server (NGINX does not refer to /etc/resolv.conf as in the first two methods).
# 公式ブログより抜粋
resolver 10.0.0.2 valid=10s;
server {
location / {
set $backend_servers backends.example.com;
proxy_pass http://$backend_servers:8080;
}
}
なお、resolver
ディレクティブで valid について指定すると TTL を無視して指定した頻度で名前解決をするようです。
ブログより抜粋
By including the valid parameter to the resolver directive, you can tell NGINX to ignore the TTL and re‑resolve names at a specified frequency instead. Here we tell NGINX to re‑resolve names every 10 seconds.
自分の場合、TTL を設定していたので valid は設定しないようにしました。