我们使用GSLB进行地理分配和负载平衡。为每项服务分配一个固定的域名。通过一些DNS魔术,域名被解析为最接近服务器且负载最小的IP。为了使负载平衡起作用,应用程序服务器需要遵守DNS响应中的TTL,并在缓存超时时再次解析域名。但是,我无法想出用Java做到这一点的方法。
该应用程序使用Java 5,在Linux(Centos 5)上运行。
答案 0 :(得分:59)
Java有一些非常奇怪的dns缓存行为。最好的办法是关闭dns缓存或将其设置为5秒的低数字。
networkaddress.cache.ttl(默认值:-1)
表示从名称服务成功进行名称查找的缓存策略。该值指定为整数,以指示缓存成功查找的秒数。值-1表示“永远缓存”。networkaddress.cache.negative.ttl(默认值:10)
表示名称服务中未成功的名称查找的缓存策略。该值指定为整数,以指示缓存未成功查找失败的秒数。值0表示“从不缓存”。值-1表示“永远缓存”。
答案 1 :(得分:58)
根据Per Byron的回答,您无法使用networkaddress.cache.ttl
标记或调用networkaddress.cache.negative.ttl
将-D
或System.setProperty
设置为系统属性,因为这些不是系统属性 - 它们是安全性属性。
如果要使用System属性触发此行为(因此可以使用-D
标志或调用System.setProperty
),则需要设置以下 System 财产:
-Dsun.net.inetaddr.ttl=0
此系统属性将启用所需的效果。
但要注意:如果在启动JVM进程时没有使用-D
标志,而是选择从代码中调用它:
java.security.Security.setProperty("networkaddress.cache.ttl" , "0")
此代码必须在JVM中的任何其他代码尝试执行网络操作之前执行。
这一点非常重要,因为,例如,如果您在.war文件中调用Security.setProperty
并将.war部署到Tomcat,这将无效:Tomcat使用Java网络堆栈进行初始化比你的.war代码被执行了。由于这种“竞争条件”,在启动JVM进程时使用-D
标志通常更方便。
如果您不使用-Dsun.net.inetaddr.ttl=0
或致电Security.setProperty
,则需要修改$JRE_HOME/lib/security/java.security
并在该文件中设置这些安全属性,例如
networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0
但要注意围绕这些属性的评论中的安全警告。只有在您有理由相信自己不受DNS spoofing attacks影响时才能这样做。
答案 2 :(得分:21)
这显然已在新版本(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();
}
}
}
答案 3 :(得分:17)
要扩展Byron的答案,我相信您需要编辑java.security
目录中的文件%JRE_HOME%\lib\security
以实现此更改。
以下是相关部分:
#
# 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
java.security
文件here上的文档。
答案 4 :(得分:6)
总结其他答案,在<jre-path>/lib/security/java.security
中,您可以设置属性networkaddress.cache.ttl
的值,以调整DNS查找的缓存方式。请注意,这不是 系统属性,而是安全属性。我能够使用以下方式设置:
java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");
这也可以由系统属性-Dsun.net.inetaddr.ttl
设置,但如果安全属性设置在别处,则不会覆盖安全属性。
我还想补充一点,如果您在WebSphere中看到Web服务的这个问题,就像我一样,设置networkaddress.cache.ttl
是不够的。您需要将系统属性disableWSAddressCaching
设置为true
。与生存时间属性不同,可以将其设置为JVM参数或通过System.setProperty
)。
IBM有一篇关于WebSphere如何处理DNS缓存here的非常详细的文章。以上相关内容是:
要禁用Web服务的地址缓存,需要将其他JVM自定义属性disableWSAddressCaching设置为true。使用此属性可禁用Web服务的地址缓存。如果您的系统通常运行大量客户端线程,并且您在wsAddrCache缓存上遇到锁争用,则可以将此自定义属性设置为true,以防止缓存Web服务数据。
答案 5 :(得分:1)
根据official oracle java properties,select cd.dept_no, d.dept_name,
count(*) as num_current,
sum(case when e.gender = 'M' then 1 else 0 end) as num_males,
sum(case when e.gender = 'F' then 1 else 0 end) as num_females
from current_dept_emp cd inner join
departments d
on cd.dept_no = d.dept_no inner join
employees e
on e.emp_no = cd.emp_no
where cd.to_date = '9999-01-01'
group by cd.dept_no
order by cd.dept_no;
是特定于Sun实现的属性,“在将来的版本中可能不支持”。 “首选方法是使用安全属性”sun.net.inetaddr.ttl
。
答案 6 :(得分:0)
所以我决定查看java源代码,因为我发现官方文档有点混乱。我发现(针对 OpenJDK 11)的内容与其他人编写的内容基本一致。重要的是属性评估的顺序。
InetAddressCachePolicy.java(为了便于阅读,我省略了一些样板文件):
String tmpString = Security.getProperty("networkaddress.cache.ttl");
if (tmpString != null) {
tmp = Integer.valueOf(tmpString);
return;
}
...
String tmpString = System.getProperty("sun.net.inetaddr.ttl");
if (tmpString != null) {
tmp = Integer.valueOf(tmpString);
return;
}
...
if (tmp != null) {
cachePolicy = tmp < 0 ? FOREVER : tmp;
propertySet = true;
} else {
/* No properties defined for positive caching. If there is no
* security manager then use the default positive cache value.
*/
if (System.getSecurityManager() == null) {
cachePolicy = 30;
}
}
您可以清楚地看到,首先评估安全属性,然后评估系统属性,如果其中任何一个被设置 cachePolicy
值被设置为该数字或 -1 (FOREVER)
,如果他们持有以下值-1.如果未设置任何内容,则默认为 30 秒。事实证明,对于 OpenJDK 来说,情况几乎总是如此,因为默认情况下 java.security
不设置该值,只有一个负值。
#networkaddress.cache.ttl=-1 <- this line is commented out
networkaddress.cache.negative.ttl=10
顺便说一句,如果 networkaddress.cache.negative.ttl
未设置(从文件中删除),java 类中的默认值为 0。这方面的文档是错误的。这就是让我绊倒的原因。