Java 內建 DNS 緩存機制,緩存正向解析結果 (域名→IP) 與負向解析結果 (域名不存在)。本文詳解緩存配置參數、代碼驗證正/負緩存行為、動態域名場景風險及最佳配置策略。
| 屬性名 | 作用 | 默認值 | 單位 | 配置方式 |
|---|---|---|---|---|
networkaddress.cache.ttl | 正向解析緩存生存時間 | -1 (永不過期) | 秒 | Security.setProperty / java.security 文件 |
networkaddress.cache.negative.ttl | 負向解析緩存生存時間 (域名不存在) | 10 | 秒 | Security.setProperty / java.security 文件 |
// 正向緩存 30 秒
java.security.Security.setProperty("networkaddress.cache.ttl", "30");
// 負向緩存 5 秒
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "5");
文件位置:$JAVA_HOME/jre/lib/security/java.security (JDK 8) 或 $JAVA_HOME/conf/security/java.security (JDK 9+)。
networkaddress.cache.ttl=30
networkaddress.cache.negative.ttl=5
ttl = -1:永久緩存,JVM 重啟前不釋放。ttl = 0:禁用緩存,每次解析都查 DNS。negative.ttl = 0:禁用負緩存,每次都查 DNS 確認不存在。public class DnsCacheDemo {
public static void main(String[] args) throws Exception {
if (args.length < 2) return; // args[0]=host, args[1]=ttl秒
Security.setProperty("networkaddress.cache.ttl", args[1]);
String host = args[0];
// 第一次解析
long t1 = System.currentTimeMillis();
InetAddress[] addrs1 = InetAddress.getAllByName(host);
System.out.println("第1次: " + (System.currentTimeMillis()-t1) + "ms");
for (InetAddress a : addrs1) System.out.println(" " + a);
System.out.print("按任意鍵繼續... "); System.in.read();
// 第二次解析
long t2 = System.currentTimeMillis();
InetAddress[] addrs2 = InetAddress.getAllByName(host);
System.out.println("第2次: " + (System.currentTimeMillis()-t2) + "ms");
for (InetAddress a : addrs2) System.out.println(" " + a);
}
}
$ java DnsCacheDemo www.126.com 5
第1次: 344ms
www.126.com/202.108.9.77
按任意鍵繼續... (5秒內按鍵)
第2次: 0ms ← 緩存命中
www.126.com/202.108.9.77
$ java DnsCacheDemo www.126.com 5
第1次: 344ms
按任意鍵繼續... (5秒後按鍵)
第2次: 484ms ← 緩存過期,重新查 DNS
www.126.com/202.108.9.77
public class NegativeCacheDemo {
public static void main(String[] args) throws Exception {
Security.setProperty("networkaddress.cache.negative.ttl", "5"); // 5秒負緩存
long t1 = System.currentTimeMillis();
try { InetAddress.getByName("www.ppp123.com"); } // 不存在域名
catch (UnknownHostException e) {
System.out.println("第1次失敗: " + (System.currentTimeMillis()-t1) + "ms");
}
// Thread.sleep(6000); // 取消註釋測試過期後
long t2 = System.currentTimeMillis();
try { InetAddress.getByName("www.ppp123.com"); }
catch (UnknownHostException e) {
System.out.println("第2次失敗: " + (System.currentTimeMillis()-t2) + "ms");
}
}
}
第1次失敗: 4688ms ← 真實 DNS 查詢超時
第2次失敗: 0ms ← 負緩存命中,即時拋異常
// 若睡眠 6 秒後:
第1次失敗: 4688ms
第2次失敗: 4420ms ← 負緩存過期,再次真實查詢
| 場景 | 風險 | 建議配置 |
|---|---|---|
| 動態域名 (DDNS、ADSL 映射) | IP 變更後客戶端仍用舊 IP,連接失敗 | ttl = 30~300 秒,平衡性能與時效性 |
| 臨時故障導致域名解析失敗 | 負緩存導致故障恢復後仍報錯,需重啟 JVM | negative.ttl = 10~60 秒,**嚴禁設 -1** |
ttl=30,配合 CoreDNS 自動更新。Security.setProperty。