DEBUG.WIKI
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
RackNerd;$21.99/年 · 1GB KVM
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Netty 短主机名首次成功,随后被搜索域的负缓存挡住

配置多个搜索域后,Netty 可能把前一个域名组合的 NXDOMAIN 当成整个短名字的失败。核对缓存、search domain 与 ndots,并区分默认缓存和自定义 resolveCache。

短主机名第一次解析成功,随后一段时间持续失败,错误却指向前一个搜索域,而且没有新的 DNS 请求发出。若 Netty 配置了多个 search domain 和大于零的 negativeTtl,要检查是否把某个域名组合的失败缓存当成了整个短名字的失败。

这条路径可在正式 Netty 4.1.137.Final 的 DnsNameResolver 中看到,正式 4.2.19.Final 仍保留同样的缓存探测判断。它不是只在某一种操作系统上才成立,也不意味着所有间歇 DNS 故障都来自缓存。

一个候选名字不存在,不代表后面的候选也不存在

假设搜索域按顺序是 a.example.com、b.example.com,要解析的是 host。前一个组合返回 NXDOMAIN,后一个组合返回地址。第一次解析可以成功,同时分别缓存前者的失败和后者的成功。

旧实现下一次先查询缓存,在搜索域循环中遇到任意非空 entry 就停止。如果最先碰到 host.a.example.com 的失败 entry,会直接使整个解析 promise 失败,不再尝试后面的搜索域。

因此,负缓存尚未过期时,即使 host.b.example.com 的成功地址还在,也可能反复失败。过期后再次解析成功,又重新留下前一个组合的负缓存,看起来便像上游 DNS 时好时坏。

核对实际 search domain 顺序、ndots、负缓存时长及错误中的完整名字,并区分“没有发出请求”与“请求发出了但未收到回复”。操作系统解析器与应用里的 Netty resolver 可以采用不同配置,命令行解析成功不能代替应用侧检查。

已知完整名字时,可以绕开搜索域展开

目标本来就是固定完整域名时,解析层可评估采用带尾点的绝对名字,例如:

host.b.example.com.

示例域名必须换成实际目标。尾点让这个 DNS 查询不再沿搜索域拼接;这不要求把 HTTP Host、TLS SNI 或证书校验名称也盲目换成带尾点的字符串。应用应保留原来的服务身份规则,并确认所用客户端如何区分解析名与逻辑服务名。

若业务必须依赖短名字及搜索域,可以在自己的 resolver 配置中临时评估关闭负缓存。假定已有 DnsNameResolverBuilder builder,对应配置为:

builder.negativeTtl(0);

这项配置针对 builder 默认创建的缓存。若已经注入自定义 resolveCache,builder 的 TTL 配置会被忽略,应按该缓存自己的负缓存策略管理,不能只加这一行就认为已有缓存行为改变了。

关闭负缓存不会关闭默认缓存的正向地址缓存,但会让不存在的候选名字更频繁地查询 DNS。应限制在受影响的 resolver,观察查询量和延迟,保留原配置以便恢复;不要为这条问题全局禁用所有缓存或改动集群的 DNS 服务。

补丁合并与正式工件需要分别核对

后续客户端应采用在搜索域探测时只接受成功缓存的实现,或具备等效行为的修正。不能只看问题已关闭,就认为手里的 4.2.19 JAR 已改变;上述正式源码仍会在任意非空 entry 上停止。

通过框架或 BOM 管理 Netty 时,按兼容方式核对实际 netty-resolver-dns,不要只替换应用里没有被使用的一个 JAR。保存版本与配置,复查第一次解析、负缓存仍有效期间的重复解析,以及缓存过期后的行为。

正确结果应是前一个域名组合不存在时,仍可使用后一个合法组合;同时,真正不存在的完整名字仍按正常错误路径返回。仅等到缓存过期后偶尔成功,不能说明问题已经消失。