DNS客户端缓存
DNS 客户端的缓存与 DNS 响应包中的 TTL 是否一致,取决于客户端的设计和配置,实际情况常常不完全一致。下面详细解释原因、保持一致的方法及常见注意事项。
1. 标准行为(“应一致”)
DNS 协议标准(如 RFC 1035)规定,递归 DNS 客户端(包括递归服务器和本地客户端)在收到响应后,应当按照响应包中的 TTL 对缓存计时,TTL 到期后删除缓存。
2. 实际实现中的差异
常见客户端行为
- 大多数操作系统的 DNS Resolver(如 Windows DNS Client、systemd-resolved)
遵循响应中的 TTL,缓存时间为 TTL 秒数。 - 浏览器、JVM、部分编程语言运行时
经常不直接遵守响应中的 TTL,而是用自己的配置参数。例如:- Java:
networkaddress.cache.ttl,默认永久缓存。 - Chrome/Firefox:有自己短周期缓存(如 60 秒),不管响应 TTL。
- Go:默认无缓存,或自定义缓存行为。
- Java:
操作系统缓存守护进程
nscd,systemd-resolved,dnsmasq等,可以配置“最小/最大 TTL”,导致缓存周期与响应 TTL 不一致。
3. 保持一致的办法
1. 系统级(守护进程)
- 确保 DNS 缓存服务(如
systemd-resolved,dnsmasq,nscd)的配置,不设置“最小/最大 TTL”,让其严格按响应包 TTL 缓存。 - 相关配置示例(以 dnsmasq 为例):
# 不强制最小/最大 TTL min-cache-ttl=0 max-cache-ttl=0
2. 应用级
- 检查并配置应用的 DNS 缓存参数,让其读取系统 resolver 缓存,或设置其缓存时间和上游 TTL 保持一致。
- Java:
-Dnetworkaddress.cache.ttl设为与期望 TTL 保持同步。 - 浏览器:一般无法控制,需知晓其行为。
- Java:
3. 递归 DNS 服务器
- 递归服务器(如 Unbound、BIND、dnsmasq)一般会严格遵循权威服务器的 TTL,但有的支持配置最小/最大 TTL。
4. 注意事项
- TTL 不等于实际缓存生效时间:
- 缓存是收到包时开始计时,传递给下级客户端时会减去已消耗的秒数(叫“剩余 TTL”)。
- 多级缓存(本地、递归、权威)会导致最终客户端看到的 TTL 可能小于最初权威服务器设置的 TTL。
- 特定场景(如 CDN、Cloudflare、运营商 DNS):运营商或中间层可能会强制修改 TTL 或缓存周期。
- 应用层缓存:应用自身不遵守 TTL 时,必须依赖开发者自行同步配置。
5. 结论与建议
- 理论上,客户端应严格按照 DNS 响应 TTL 缓存。
- 实际情况需手动配置/验证:操作系统和应用级缓存都要检查和设置参数。
- 多级缓存会导致 TTL 递减,不能简单认为客户端缓存时间等于权威 TTL。
参考配置示例
# dnsmasq 严格按上游 TTL 缓存
min-cache-ttl=0
max-cache-ttl=0
# Java 严格按系统 resolver
-Dnetworkaddress.cache.ttl=-1
如需确保一致,建议:
- 配置本地/系统 DNS 缓存服务严格遵守 TTL。
- 配置应用程序 DNS 缓存参数为“读取系统”或与 TTL 保持同步。
- 定期测试和验证 TTL 生效行为。
如需针对某操作系统、应用或服务的具体配置方法,请说明详细环境。
Kona JDK
Kona JDK(腾讯基于OpenJDK优化的发行版)的DNS缓存机制遵循OpenJDK标准,其默认缓存行为及配置规则如下:
⚙️ 一、默认缓存策略
-
成功解析的DNS记录
- 未显式配置时:默认缓存时间为 30秒(与标准OpenJDK行为一致)[citation:1][citation:2][citation:7]。
- 逻辑依据:
- 若未启用
SecurityManager且未配置networkaddress.cache.ttl参数,则使用30秒作为默认值[citation:1][citation:6]。 - 若启用
SecurityManager,则优先读取${JAVA_HOME}/jre/lib/security/java.security中的配置[citation:1]。
- 若未启用
-
解析失败的DNS记录(负缓存)
- 默认永久缓存:若域名解析失败(如UnknownHostException),JVM会永久缓存失败结果(即
networkaddress.cache.negative.ttl默认值为-1)[citation:1][citation:7]。 - 风险:可能导致后续解析请求始终失败,需显式配置负缓存时间避免此问题。
- 默认永久缓存:若域名解析失败(如UnknownHostException),JVM会永久缓存失败结果(即
🔧 二、配置参数与优先级
通过以下参数调整缓存时间(优先级从高到低):
-
java.security文件配置
修改路径:${JAVA_HOME}/conf/security/java.security
添加:networkaddress.cache.ttl=60 # 成功解析缓存60秒 networkaddress.cache.negative.ttl=10 # 失败解析缓存10秒[citation:1][citation:7]
-
JVM启动参数
命令行覆盖:java -Dnetworkaddress.cache.ttl=300 -Dnetworkaddress.cache.negative.ttl=30 -jar app.jar[citation:2][citation:4]
-
程序代码动态设置
java.security.Security.setProperty("networkaddress.cache.ttl", "60");(需在首次DNS查询前调用)[citation:1]
⚠️ 优先级规则:
java.security> JVM启动参数 > 默认值
若配置为0,表示禁用缓存;-1表示永久缓存[citation:1][citation:6]。
📊 三、生产环境建议
| 场景 | 推荐配置 |
|---|---|
| 频繁变更IP的服务 | 成功缓存TTL≤60秒(如-Dnetworkaddress.cache.ttl=30) |
| 高稳定性环境 | 成功缓存TTL=300~600秒,负缓存TTL=60秒(平衡性能与容错) |
| 需快速感知DNS故障切换 | 负缓存TTL≤30秒(避免永久阻塞重试) |
🔍 四、验证缓存生效
- 查看当前配置
System.out.println("Cache TTL: " + java.security.Security.getProperty("networkaddress.cache.ttl")); - 测试缓存行为
修改/etc/hosts文件模拟DNS变更,观察控制台输出是否在TTL后更新IP[citation:1]。
⚠️ 五、常见问题与规避
- 容器环境问题:Kona JDK在容器中可能因默认配置导致缓存过长,建议显式设置TTL[citation:4]。
- 云服务依赖:若使用腾讯云微服务框架(如TSF),结合Service Mesh时需同步调整服务发现的DNS缓存策略[citation:5]。
- 负缓存超时:务必显式配置
networkaddress.cache.negative.ttl(如30秒),避免永久失败[citation:1][citation:7]。
💡 最佳实践:在云原生场景中,建议通过JVM参数统一管理DNS缓存(如
-Dnetworkaddress.cache.ttl=60),而非依赖默认值,确保跨环境一致性[citation:4][citation:6]。

浙公网安备 33010602011771号