我有一个小 Java 程序,每秒循环调用 InetAddress.getByName("example.com")。当我使用“strace -f”在 CentOS 6.4 机器上运行它时,我看到 /etc/resolv.conf 被打开并读取一次:
$ 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
两个系统都没有运行名称缓存守护进程。
我在两台机器上使用相同版本的 Oracle HotSot Java JVM 来排除任何 Java 差异。
CentOS 6.4 盒安装了 glibc 2.12。Debian 7 盒安装了 glibc 2.13。
什么原因导致两个操作系统在打开和读取 /etc/resolv.conf 时的行为不同?
答案1
RedHat glibc 开发人员认为他们软件中的一些错误不算是错误。这些错误之一就是在更改 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
),因此名称查找系统调用的实际实现完全不同。
这可能解释了这两个发行版之间不同的系统调用行为。
我假设InetAddress.getByName
翻译成getaddrinfo()
。您可以先阅读相关 C 库实现和版本中每个系统调用的源代码。
确保阅读您正在使用的实际软件包版本的源代码。与原始上游版本相比,EL 6.4 中的软件包已经进行了超过 2 年的改进。我认为 Debian 软件包也是如此。