名前解決遅延と対策について

私もよく混乱するのですが、

dnsの問い合わせで遅延が発生するパターンは二つあります。

1.resolv.conf上位のDNSキャッシュサーバがホストダウン中に
2番手のネームサーバへの切り替えるため遅延が発生する。
デフォルト設定では5秒待ってから次のサーバを試す。
2.RHEL6系からAとAAAAレコードが同じソケットでの問い合わせを行うため
対応していないfirewallやブロードバンドルータ配下のホストでは遅延が発生する。
AとAAAAレコードの二つのレコード結果の両方が揃うまで待ち続けるため、
その待ちがタイムアウトするまで5秒遅延が発生する。

どちらも5秒待つことになるので同じ問題なんだと考え深みにはまる。

1については「DNSキャッシュサーバのメンテナンスや障害時の影響と対策」でお話ししましたが、ここでは2について触れます。

2の場合でも混乱ポイントがあって、同じバージョンであっても問題がでる場合とでない場合があるということを留意しておく必要がありますのでご注意ください。

我々の環境ではバックボーン環境やサーバで構築しているNATサーバ、firewallや負荷分散装置配下のRHEL6系のホストでは遅延は発生していません。

一方でオフィスのBフレッツ回線配下に設置するRHEL6系のOSはことごとく遅延してしまいます。

裏は取れていないのですが、上流のブロードバンドルータが同一ソケットでの問い合わせに対応できずパケットを落としてしまうため問題が発生していると推測しています。

ということで、上記を踏まえつつ今件をどのように対応するかについてなんですが、

3つの方法が考えられます。

■ひとつめ

A、AAAAレコードを同一ソケットで問い合わせが出来る機器で構成する。

■ふたつめ

みなさんご存じのresolv.confでの設定

options single-request-reopen

もしくは

options single-request

で対応していくことになるかと思います。

このオプション使用前と後でのtcpdumpで改善したかどうか確認してみましょう。

■オプション使用前

[root@srv2271 ~]# tcpdump port 53 -n
23:15:28 IP 10.163.0.169.35504 > 8.8.8.8.domain: 20366+ A? www.dmm.com. (29)
23:15:28 IP 10.163.0.169.35504 > 8.8.8.8.domain: 25440+ AAAA? www.dmm.com. (29)
23:15:28 IP 8.8.8.8.domain > 10.163.0.169.35504: 20366 1/0/0 A 203.209.152.96 (45)
23:15:33 IP 10.163.0.169.35504 > 8.8.8.8.domain: 20366+ A? www.dmm.com. (29)
23:15:33 IP 8.8.8.8.domain > 10.163.0.169.35504: 20366 1/0/0 A 203.209.152.96 (45)
23:15:33 IP 10.163.0.169.35504 > 8.8.8.8.domain: 25440+ AAAA? www.dmm.com. (29)
23:15:33 IP 8.8.8.8.domain > 10.163.0.169.35504: 25440 0/0/0 (29)

AとAAAAレコードが同じソケット(35504)で問い合わせを行い
Aレコードは返答が来ているがAAAAレコードを待っているため5秒待っているのが分かる。
■オプション使用後

$ sudo tcpdump port 53 -n
23:16:05 IP 10.163.0.169.48690 > 8.8.8.8.domain: 27161+ A? www.dmm.com. (29)
23:16:05 IP 8.8.8.8.domain > 10.163.0.169.48690: 27161 1/0/0 A 203.209.152.96 (45)
23:16:05 IP 10.163.0.169.52755 > 8.8.8.8.domain: 34677+ AAAA? www.dmm.com. (29)
23:16:06 IP 8.8.8.8.domain > 10.163.0.169.52755: 34677 0/0/0 (29)

こちらは別ソケット(Aレコードは48690、AAAAレコードは52755)で
順番に問い合わせしているので遅延は発生していないのがわかる。

■みっつめ

OS側でipv6をdisableとすると改善します。

上記のいずれかの対応を自身の環境に合わせて適用していけばよさそうです。

それにしても、ほんと混乱します。

システムコールやコマンドごとに挙動が違うことも問題を複雑化させているように思います。

traceroute、curlは遅延しますし、

ping、digやnslookupなどは遅延しません。

例えばpingで確認してしまうと直ったと勘違いしてしまうことになります。^^;

とりあえずは、標準化の策定の中でsingle-requestを入れておくというのが正解なんだと思います。

最後に小ネタをひとつ

curlコマンドはオプションで[-4]を利用すると遅延が改善します。

DNSキャッシュサーバのメンテナンスや障害時の影響と対策

DNSキャッシュサーバのメンテナンスや障害時の影響と対策

みなさん、サーバ構築する際/etc/resolv.confでnameserverの設定をされているかと思います。

ここに指定しているDNSキャッシュサーバで障害が発生しホストダウンとなると
resolv.confで設定した次のネームサーバへ問い合わせるまである一定の時間待たされ影響が出ることがあります。

標準のタイムアウト値は5秒なんですが復旧するまでの名前解決はそれぞれずっと5秒間遅延することになりますのでdmmでは意外と影響が大きくなります。

IPは生きていてdnsサービス自体が落ちている場合はすぐに次のDNSキャッシュサーバに切り替わるのですが、
IPの接続性がなくなるホストダウンとなるとタイムアウト値まで待たされることになりますので注意が必要です。

存在しないIPアドレス:10.255.255.255
存在するがDNSサーバではない:10.163.0.226
動作中のローカルDNSキャッシュ:127.0.0.1

の組み合わせでテストしてみました。結果は下記です。

■5秒待たされる場合のstrace結果

10.255.255.255を試し、タイムアウト(5秒)まで待たされて127.0.0.1へ問い合わせしているのがわかります。

23:35:13 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
23:35:13 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.255.255.255")}, 16) = 0
23:35:13 poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
23:35:13 sendto(3, "\320\276\1\0\0\1\0\0\0\0\0\0\3www\3dmm\3com\0\0\1\0\1", 29, MSG_NOSIGNAL, NULL, 0) = 29
23:35:13 poll([{fd=3, events=POLLIN}], 1, 5000) = 0 (Timeout)
23:35:18 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 4
23:35:18 connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
23:35:18 poll([{fd=4, events=POLLOUT}], 1, 0) = 1 ([{fd=4, revents=POLLOUT}])
23:35:18 sendto(4, "\320\276\1\0\0\1\0\0\0\0\0\0\3www\3dmm\3com\0\0\1\0\1", 29, MSG_NOSIGNAL, NULL, 0) = 29
23:35:18 poll([{fd=4, events=POLLIN}], 1, 3000) = 1 ([{fd=4, revents=POLLIN}])
23:35:18 ioctl(4, FIONREAD, [45])       = 0
23:35:18 recvfrom(4, "\320\276\201\200\0\1\0\1\0\0\0\0\3www\3dmm\3com\0\0\1\0\1\300\f\0"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, [16]) = 45
23:35:18 close(3)                       = 0
23:35:18 close(4)                       = 0
23:35:18 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
23:35:18 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
23:35:18 fcntl(3, F_GETFL)              = 0x2 (flags O_RDWR)
23:35:18 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
23:35:18 connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("203.209.152.96")}, 16) = -1 EINPROGRESS (Operation now in progress)
■すぐに切り替わる場合のstrace結果

10.163.0.226を試してすぐにPOLLERRとなりすぐに127.0.0.1へ問い合わせしているのがわかります。

23:39:05 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
23:39:05 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.163.0.226")}, 16) = 0
23:39:05 poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
23:39:05 sendto(3, "\261\320\1\0\0\1\0\0\0\0\0\0\3www\3dmm\3com\0\0\1\0\1", 29, MSG_NOSIGNAL, NULL, 0) = 29
23:39:05 poll([{fd=3, events=POLLIN}], 1, 5000) = 1 ([{fd=3, revents=POLLERR}])
23:39:05 close(3)                       = 0
23:39:05 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
23:39:05 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
23:39:05 poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
23:39:05 sendto(3, "\261\320\1\0\0\1\0\0\0\0\0\0\3www\3dmm\3com\0\0\1\0\1", 29, MSG_NOSIGNAL, NULL, 0) = 29
23:39:05 poll([{fd=3, events=POLLIN}], 1, 3000) = 1 ([{fd=3, revents=POLLIN}])
23:39:05 ioctl(3, FIONREAD, [45])       = 0
23:39:05 recvfrom(3, "\261\320\201\200\0\1\0\1\0\0\0\0\3www\3dmm\3com\0\0\1\0\1\300\f\0"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, [16]) = 45
23:39:05 close(3)                       = 0
23:39:05 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
23:39:05 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
23:39:05 fcntl(3, F_GETFL)              = 0x2 (flags O_RDWR)
23:39:05 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
23:39:05 connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("203.209.152.96")}, 16) = -1 EINPROGRESS (Operation now in progress)

ということでこれらの影響を最小限とするため下記のような対策が必要になってくると思っています。

1.タイムアウト値を調整し障害発生時でも影響を最小限に

resolv.confでのタイムアウト値を規定の5秒から1秒へ変更

options timeout:1
2.そもそもDNSキャッシュサーバを落とさない構成

lvs配下にDNSキャッシュサーバを2台以上配置。
その構成を2セット用意してそもそも落とさない
3.各サーバでdnsmasqやunboundを導入し切り替え時間を高速化する。

resolv.confに
nameserver 127.0.0.1

として
一番上にローカルにインストールされたDNSキャッシュサーバを指定しておく。

※ローカルのIPは落ちることがないのでローカルにインストールされた
DNSキャッシュが停止したとしてもすぐに切り替わる。
4.hostsを利用しそもそもDNSキャッシュサーバに頼らない。

分かり切った相手先への通信を行うサーバについてはhostsを利用し、
そもそもDNSキャッシュサーバを利用しない。
5.DNSキャッシュアプライアンスを導入する。
6.外部のDNSキャッシュサービスを利用する。

上記6つの対策はどれも正解でそれぞれを適材適所で利用することになるんだと思います。

dmmでは

DNSキャッシュサーバを落とさない設計

プラス

各サーバのローカル環境にDNSキャッシュサーバをインストールし、さらに一部hostsも利用し低レイテンシーを実現する方向で対策を行います。

最近は各社さんとの連携のため多くの通信が発生し、その通信に低レイテンシーさが求められるようになってきているためhostsを使ったりunboundやdnsmasqなどのDNSキャッシュを利用する構成をとります。

みなさんはどのような対策を行っていますでしょうか?

コメントorツイートいただけると嬉しいです。

お仲間いませんかね?SPF設定

 

「SPF」

差出人ドメインのなりすましを防ぐための認証技術としてSPFは一番普及しているのではないかと思います。

大手のプロバイダがこのSPFレコードを使い迷惑メールへの分類を開始していることもあり、

ほとんどの方が設定しているのではないかと思います。

SPFレコードは

SPF(type99)レコードか、SPFフォーマットのTXTレコードで公開します。

ちょっとややこしいのでdmmの例を出します。

dmm.com. 900 IN TXT “v=spf1 ip4:203.209.144.0/20 ip4:113.157.232.128/25 ip4:118.159.239.0/26 ip4:202.6.244.0/22 -all”
dmm.com. 900 IN SPF “v=spf1 ip4:203.209.144.0/20 ip4:113.157.232.128/25 ip4:118.159.239.0/26 ip4:202.6.244.0/22 -all”

上段がSPFフォーマットでTXTレコードで公開

下段がSPF(type99)レコードで公開

ほとんどのプロバイダがTXTレコードをみてなりすましの確認をしているので、

dmmでもSPFフォーマットのTXTレコードで公開しています。

が、

dmmではさらにSPF(type99)レコードでも公開するようにしています。

dnsの情報は他社のものも確認できるので各社と足並みをそろえるようにしてはいるのですが、

どうも、大手(google,twitter,facebookなどなど)ではTXTレコードしか使ってないようです。

当然、みんな設定しているものと思っていたので、

なんか、はしごを外された気分。(>_<) 私の理解ではキャッシュ問題を吸収するような余裕をもったスケジュールでSPFレコードを取り扱えばそれほどデメリットは感じられません。 今後SPF(type99)だけで確認するプロバイダも出てくると仮定しておくのが自然だと思うので、 最初から設定しておけばいいのになと思っている次第です。 何かほかにもデメリットがあるんですかね? みなさんの見解をお待ちしております。 とりあえず、dmmでは1年以上どちらも設定しているのですが特に問題ないのですが。