毎秒 InetAddress.getByName("example.com") を呼び出しループする小さな Java プログラムがあります。これを CentOS 6.4 ボックスで 'strace -f' を使用して実行すると、/etc/resolv.conf が開かれ、1 回読み取られることがわかります。
$ grep /etc/resolv.conf strace.out
[pid 24810] open("/etc/resolv.conf", O_RDONLY) = 6
Debian 7 で実行すると、/etc/resolv.conf が繰り返し開かれたり stat() されたりしていることがわかります。
$ grep /etc/resolv.conf strace.out
[pid 41821] open("/etc/resolv.conf", O_RDONLY) = 10
[pid 41821] stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=92, ...}) = 0
[pid 41821] open("/etc/resolv.conf", O_RDONLY) = 10
[pid 41821] stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=92, ...}) = 0
[pid 41821] stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=92, ...}) = 0
どちらのシステムも/etc/nsswitch.confが次のように設定されている。
ホスト: ファイル DNS
どちらのシステムでも名前キャッシュ デーモンは実行されていません。
Java の違いを排除するために、両方のマシンで同じバージョンの Oracle HotSot Java JVM を使用しました。
CentOS 6.4 ボックスには glibc 2.12 がインストールされています。Debian 7 ボックスには glibc 2.13 がインストールされています。
/etc/resolv.conf を開いて読み取る際に、2 つのオペレーティング システム間で動作が異なるのはなぜでしょうか?
答え1
RedHat glibc 開発者は、ソフトウェア内の一部のバグをバグではないと考えています。これらのバグの 1 つは、変更後の resolv.conf の再読み込みです。glibc はそれをアプリケーションの責任と見なしているため、各アプリケーションはこれに対して独自のロジックを作成する必要があります。
これはまったくおかしなことなので、eglibc 開発者はこの問題を修正しました。そのため、eglibc 以外のシステムでは、アプリケーションに nss_dns を再初期化するための独自のロジックを持たせるか、resolv.conf の変更後に再起動する必要があります。eglibc システム (Debian および Debian ベースのもの) では、バグの少ない libc が提供されます。
resolv.conf を変更し、古い DNS サーバーを廃止し、1200 台以上の MySQL サーバーを再起動した後に、このことを痛感しました。言うまでもなく、これは楽しいことではありません。
答え2
C ライブラリのバージョンが異なるだけでなく、CentOS は GNU C ライブラリ ( glibc
) を使用するのに対し、Debian は組み込み GLIBC ( eglibc
) を使用するため、名前検索システム コールの実際の実装はまったく異なります。
おそらく、この 2 つのディストリビューション間でシステム コールの動作が異なるのはそのためでしょう。
InetAddress.getByName
と解釈されると思いますgetaddrinfo()
。まずは、関連する C ライブラリの実装とバージョンで各システムコールのソースを読んでみてください。
実際に使用しているパッケージ バージョンのソースを必ず読んでください。EL 6.4 のパッケージは、元のアップストリーム バージョンと比較して 2 年以上にわたって改良されています。Debian パッケージでも同じことが言えると思います。