如何让 Java 遵守 DNS 缓存超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1256556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make Java honor the DNS Caching Timeout?
提问by ZZ Coder
We use GSLB for geo-distribution and load-balancing. Each service is assigned a fixed domain name. Through some DNS magic, the domain name is resolved into an IP that's closest to the server with least load. For the load-balancing to work, the application server needs to honor the TTL from DNS response and to resolve the domain name again when cache times out. However, I couldn't figure out a way to do this in Java.
我们使用 GSLB 进行地理分布和负载平衡。每个服务都分配了一个固定的域名。通过一些 DNS 魔法,域名被解析为最接近服务器且负载最小的 IP。为了负载平衡工作,应用服务器需要接受来自 DNS 响应的 TTL 并在缓存超时时再次解析域名。但是,我想不出在 Java 中执行此操作的方法。
The application is in Java 5, running on Linux (Centos 5).
该应用程序采用 Java 5,在 Linux (Centos 5) 上运行。
回答by Byron Whitlock
Java has some seriously weird dns caching behavior. Your best bet is to turn off dns caching or set it to some low number like 5 seconds.
Java 有一些非常奇怪的 dns 缓存行为。最好的办法是关闭 dns 缓存或将其设置为某个较低的数字,例如 5 秒。
networkaddress.cache.ttl (default: -1)
Indicates the caching policy for successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the successful lookup. A value of -1 indicates "cache forever".networkaddress.cache.negative.ttl (default: 10)
Indicates the caching policy for un-successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the failure for un-successful lookups. A value of 0 indicates "never cache". A value of -1 indicates "cache forever".
networkaddress.cache.ttl(默认值:-1)
指示从名称服务成功查找名称的缓存策略。该值指定为整数以指示缓存成功查找的秒数。值 -1 表示“永远缓存”。networkaddress.cache.negative.ttl(默认值:10)
指示名称服务不成功的名称查找的缓存策略。该值指定为整数,以指示为不成功的查找缓存失败的秒数。值 0 表示“从不缓存”。值 -1 表示“永远缓存”。
回答by matt b
To expand on Byron's answer, I believe you need to edit the file java.security
in the %JRE_HOME%\lib\security
directory to effect this change.
为了扩展拜伦的答案,我相信您需要编辑目录java.security
中的%JRE_HOME%\lib\security
文件以实现此更改。
Here is the relevant section:
这是相关部分:
#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
# serious security implications. Do not set it unless
# you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1
Documentation on the java.security
file here.
此处的java.security
文件文档。
回答by user1050755
This has obviously been fixed in newer releases (SE 6 and 7). I experience a 30 second caching time max when running the following code snippet while watching port 53 activity using tcpdump.
这显然已在较新的版本(SE 6 和 7)中得到修复。在使用 tcpdump 观察端口 53 活动的同时运行以下代码片段时,我遇到了最长 30 秒的缓存时间。
/**
* http://stackoverflow.com/questions/1256556/any-way-to-make-java-honor-the-dns-caching-timeout-ttl
*
* Result: Java 6 distributed with Ubuntu 12.04 and Java 7 u15 downloaded from Oracle have
* an expiry time for dns lookups of approx. 30 seconds.
*/
import java.util.*;
import java.text.*;
import java.security.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class Test {
final static String hostname = "www.google.com";
public static void main(String[] args) {
// only required for Java SE 5 and lower:
//Security.setProperty("networkaddress.cache.ttl", "30");
System.out.println(Security.getProperty("networkaddress.cache.ttl"));
System.out.println(System.getProperty("networkaddress.cache.ttl"));
System.out.println(Security.getProperty("networkaddress.cache.negative.ttl"));
System.out.println(System.getProperty("networkaddress.cache.negative.ttl"));
while(true) {
int i = 0;
try {
makeRequest();
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println(new Date());
inetAddress = InetAddress.getByName(hostname);
displayStuff(hostname, inetAddress);
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
Thread.sleep(5L*1000L);
} catch(Exception ex) {}
i++;
}
}
public static void displayStuff(String whichHost, InetAddress inetAddress) {
System.out.println("Which Host:" + whichHost);
System.out.println("Canonical Host Name:" + inetAddress.getCanonicalHostName());
System.out.println("Host Name:" + inetAddress.getHostName());
System.out.println("Host Address:" + inetAddress.getHostAddress());
}
public static void makeRequest() {
try {
URL url = new URL("http://"+hostname+"/");
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
InputStreamReader ird = new InputStreamReader(is);
BufferedReader rd = new BufferedReader(ird);
String res;
while((res = rd.readLine()) != null) {
System.out.println(res);
break;
}
rd.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
回答by Les Hazlewood
Per Byron's answer, you can't set networkaddress.cache.ttl
or networkaddress.cache.negative.ttl
as System Properties by using the -D
flag or calling System.setProperty
because these are not System properties - they are Securityproperties.
根据拜伦的回答,您不能通过使用标志或调用来设置networkaddress.cache.ttl
或networkaddress.cache.negative.ttl
作为系统属性,因为这些不是系统属性 - 它们是安全属性。-D
System.setProperty
If you want to use a System property to trigger this behavior (so you can use the -D
flag or call System.setProperty
), you will want to set the following Systemproperty:
如果您想使用 System 属性来触发此行为(以便您可以使用-D
flag 或 call System.setProperty
),您需要设置以下System属性:
-Dsun.net.inetaddr.ttl=0
This system property will enable the desired effect.
此系统属性将启用所需的效果。
But be aware: if you don't use the -D
flag when starting the JVM process and elect to call this from code instead:
但请注意:如果您-D
在启动 JVM 进程时不使用该标志并选择从代码中调用它:
java.security.Security.setProperty("networkaddress.cache.ttl" , "0")
This code mustexecute before any other code in the JVM attempts to perform networking operations.
此代码必须在 JVM 中的任何其他代码尝试执行网络操作之前执行。
This is important because, for example, if you called Security.setProperty
in a .war file and deployed that .war to Tomcat, this wouldn't work: Tomcat uses the Java networking stack to initialize itself much earlier than your .war's code is executed. Because of this 'race condition', it is usually more convenient to use the -D
flag when starting the JVM process.
这很重要,因为例如,如果您调用Security.setProperty
.war 文件并将该 .war 部署到 Tomcat,这将不起作用:Tomcat 在执行 .war 代码之前使用 Java 网络堆栈来初始化自身。由于这种“竞争条件”,-D
在启动 JVM 进程时使用该标志通常更方便。
If you don't use -Dsun.net.inetaddr.ttl=0
or call Security.setProperty
, you will need to edit $JRE_HOME/lib/security/java.security
and set those security properties in that file, e.g.
如果您不使用-Dsun.net.inetaddr.ttl=0
或调用Security.setProperty
,则需要$JRE_HOME/lib/security/java.security
在该文件中编辑和设置这些安全属性,例如
networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0
But pay attention to the security warnings in the comments surrounding those properties. Only do this if you are reasonably confident that you are not susceptible to DNS spoofing attacks.
但请注意围绕这些属性的评论中的安全警告。仅当您有理由确信您不会受到DNS 欺骗攻击时才这样做。
回答by thesquaregroot
To summarize the other answers, in <jre-path>/lib/security/java.security
you can set the value of the property networkaddress.cache.ttl
to adjust how DNS lookups are cached. Note that this is nota system property but a security property. I was able to set this using:
总结其他答案,<jre-path>/lib/security/java.security
您可以设置属性的值networkaddress.cache.ttl
来调整 DNS 查找的缓存方式。请注意,这不是系统属性,而是安全属性。我能够使用以下方法进行设置:
java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");
This can also be set by the system property -Dsun.net.inetaddr.ttl
though this will not override a security property if it is set elsewhere.
这也可以由系统属性设置,-Dsun.net.inetaddr.ttl
但如果它在其他地方设置,则不会覆盖安全属性。
I would also like to add that if you are seeing this issue with web services in WebSphere, as I was, setting networkaddress.cache.ttl
will not be enough. You need to set the system property disableWSAddressCaching
to true
. Unlike the time-to-live property, this can be set as a JVM argument or via System.setProperty
).
我还想补充一点,如果您在 WebSphere 中看到 Web 服务的这个问题,就像我一样,设置networkaddress.cache.ttl
是不够的。您需要将系统属性设置disableWSAddressCaching
为true
. 与生存时间属性不同,这可以设置为 JVM 参数或通过System.setProperty
)。
IBM has a pretty detailed post on how WebSphere handles DNS caching here. The relevant piece to the above is:
IBM 在此处有一篇关于 WebSphere 如何处理 DNS 缓存的非常详细的文章。与上述相关的部分是:
To disable address caching for Web services, you need to set an additional JVM custom property disableWSAddressCaching to true. Use this property to disable address caching for Web services. If your system typically runs with lots of client threads, and you encounter lock contention on the wsAddrCache cache, you can set this custom property to true, to prevent caching of the Web services data.
要禁用 Web 服务的地址缓存,您需要将额外的 JVM 定制属性 disableWSAddressCaching 设置为 true。使用此属性可禁用 Web 服务的地址缓存。如果您的系统通常使用大量客户端线程运行,并且您遇到 wsAddrCache 缓存上的锁争用,您可以将此定制属性设置为 true,以防止缓存 Web 服务数据。
回答by CloudStax
According to the official oracle java properties, sun.net.inetaddr.ttl
is Sun implementation-specific property, which "may not be supported in future releases". "the preferred way is to use the security property" networkaddress.cache.ttl
.
根据官方的 oracle java properties,sun.net.inetaddr.ttl
是 Sun 实现特定的属性,“在未来版本中可能不支持”。“首选方法是使用安全属性” networkaddress.cache.ttl
。