11

如果我得到一个初始的“名称或服务未知”(EAI_NONAME),对 getaddrinfo() 的下一次调用似乎直接进入 dns 而不是首先检查缓存(nscd 日志显示没有查找尝试,tcpdump 显示到 DNS 服务器的流量)。如果第一次调用成功获取地址,那么从那时起,所有 getaddrinfo() 调用都会按预期首先转到 nscd。

我正在为 arm linux 编译 glibc-2.13。在我的 rc.d 中,nscd 在我的守护进程之前启动。nscd 设置为禁止共享缓存,并维护主机缓存。我正在使用来自busybox(0.47)的nscd。nsswitch.conf 已设置,以便主机检查缓存/文件/dns。hosts.conf 设置为检查文件/绑定。

我的守护进程正在调用 getaddrinfo()。

我有运行 nscd 的调试日志,它们显示客户端开始读取 DNS 响应并以“Broken Pipe”错误关闭。

之后,它会显示来自其他守护进程尝试使用缓存的 GAI 尝试(所以我知道它没有被 nscd 锁定或其他任何东西),但获得 EAI_NONAME 的守护进程再也不会联系 nscd 进行缓存查找。

如果我重新启动守护程序,我会得到相同的行为,如果第一个 DNS 查询再次超时。

glibc 中有什么东西使我的守护进程到缓存的链接无效吗?有没有办法将我的守护进程重新连接到缓存而不重新启动它(类似于通过 res_init() 强制 resolv.conf 重新加载)?

4

1 回答 1

5

正如alk 在他的评论中提到的那样,重试getaddrinfo()100 次以上应该会强制执行 nscd 查询。


要了解原因,让我们快速了解一下getaddrinfo()内部 的执行流程。

  1. getaddrinfo()调用 gaih_inet

  2. gaih_inet() 对 执行以下操作__nss_not_use_nscd_hosts

    • 检查它是否为正整数?
    • 递增它。
    • 检查它是否超过重试次数NSS_NSCD_RETRY

      • 仅当满足上述两个条件时,它才会尝试查询 nscd。

      • 同样,在尝试查询 nscd 时,计数会立即重置为零,
        从而在下NSS_NSCD_RETRY一次getaddrinfo()调用时忽略 nscd。

  3. __nss_not_use_nscd_hosts由 nscd 在以下位置进行内部修改

综上所述,可以断定
getaddrinfo()不是每次都查询nscd。

nscd 的内部状态(由 确定__nss_not_use_nscd_hosts
决定是否getaddrinfo()最终调用 nscd。

要真正绕过 100 次重试限制,可以修改 NSS_NSCD_RETRY和重建 libc 以偏离标准行为。但我不确定这是否不会导致任何其他意外的回归。

参考:引入逻辑的补丁__nss_not_use_nscd_hostsgetaddrinfo()

于 2013-07-30T04:38:35.180 回答