如何让 Java 遵守 DNS 缓存超时?
我们使用 GSLB 进行地理分布和负载平衡。 每个服务都分配有一个固定的域名。 通过一些 DNS 魔法,域名会被解析为最接近负载最小的服务器的 IP。 为了使负载平衡发挥作用,应用程序服务器需要遵守 DNS 响应的 TTL,并在缓存超时时再次解析域名。 但是,我无法找到在 Java 中执行此操作的方法。
该应用程序采用 Java 5 编写,在 Linux (Centos 5) 上运行。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
根据 Byron 的回答,您无法使用
-D
networkaddress.cache.ttl 或networkaddress.cache.male.ttl
设置为系统属性> 标志或调用System.setProperty
因为这些不是系统属性 - 它们是安全属性。如果您想使用系统属性来触发此行为(因此您可以使用
-D
标志或调用System.setProperty
),您将需要设置以下< em>系统属性:此系统属性将启用所需的效果。 这里的“0”(零)表示在 JVM 级别禁用 DNS 缓存,因此将查询并使用来自 DNS 的原始 TTL 值。
但请注意:如果您在启动 JVM 进程时不使用
-D
标志并选择从代码中调用它:此代码必须在任何其他代码之前执行在 JVM 中尝试执行网络操作。
这很重要,因为例如,如果您在 .war 文件中调用
Security.setProperty
并将该 .war 部署到 Tomcat,则这将不起作用:Tomcat 使用 Java 网络堆栈来初始化自身早于 .war 的代码执行。 由于这种“竞争条件”,在启动 JVM 进程时使用-D
标志通常会更方便。如果您不使用
-Dsun.net.inetaddr.ttl=0
或调用Security.setProperty
,则需要编辑$JRE_HOME/lib/security /java.security
并在该文件中设置这些安全属性,例如,但请注意围绕这些属性的注释中的安全警告。 仅当您相当确信自己不会受到 DNS 欺骗攻击时才执行此操作。
值得注意的是 Oracle JDK 8 文档推荐方法是使用
networkaddress.cache.ttl
和networkaddress.cache.negative.ttl
,如官方文档中所述。 这两个属性无法在命令行中设置,但应使用 setProperty() 或利用安全策略文件进行设置。Per Byron's answer, you can't set
networkaddress.cache.ttl
ornetworkaddress.cache.negative.ttl
as System Properties by using the-D
flag or callingSystem.setProperty
because these are not System properties - they are Security properties.If you want to use a System property to trigger this behavior (so you can use the
-D
flag or callSystem.setProperty
), you will want to set the following System property:This system property will enable the desired effect. "0" (Zero) here means disable DNS caching at the JVM level, thus the original TTL value from the DNS will be consulted and used.
But be aware: if you don't use the
-D
flag when starting the JVM process and elect to call this from code instead:This code must execute before any other code in the JVM attempts to perform networking operations.
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.If you don't use
-Dsun.net.inetaddr.ttl=0
or callSecurity.setProperty
, you will need to edit$JRE_HOME/lib/security/java.security
and set those security properties in that file, e.g.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.
It is worth noting that the Oracle JDK 8 docs recommended approach is to to use
networkaddress.cache.ttl
andnetworkaddress.cache.negative.ttl
as already described in the official documentation here. These two properties cannot be set at the command line but should be set usingsetProperty()
or utilize the security policy file.Java 有一些非常奇怪的 dns 缓存行为。 最好的办法是关闭 dns 缓存或将其设置为某个较低的数字,例如 5 秒。
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.
这显然已在较新的版本(SE 6 和 7)中得到修复。 当运行以下代码片段并使用 tcpdump 观察端口 53 活动时,我遇到的最大缓存时间为 30 秒。
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.
为了扩展拜伦的答案,我相信您需要编辑
%JRE_HOME%\lib\security
目录中的文件java.security
才能实现此更改。以下是相关部分:
关于
java.security
文件 此处。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.Here is the relevant section:
Documentation on the
java.security
file here.总结其他答案,在
/lib/security/java.security
中,您可以设置属性networkaddress.cache.ttl
的值来调整如何缓存 DNS 查找。 请注意,这不是系统属性,而是安全属性。 我可以使用以下方法进行设置:这也可以通过系统属性
-Dsun.net.inetaddr.ttl
设置,尽管如果在其他地方设置,这不会覆盖安全属性。我还想补充一点,如果您像我一样在 WebSphere 中的 Web 服务中遇到此问题,那么设置
networkaddress.cache.ttl
是不够的。 您需要将系统属性disableWSAddressCaching
设置为true
。 与生存时间属性不同,它可以设置为 JVM 参数或通过 System.setProperty 进行设置。IBM 在此处。 与上述相关的部分是:
To summarize the other answers, in
<jre-path>/lib/security/java.security
you can set the value of the propertynetworkaddress.cache.ttl
to adjust how DNS lookups are cached. Note that this is not a system property but a security property. I was able to set this using: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.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 propertydisableWSAddressCaching
totrue
. Unlike the time-to-live property, this can be set as a JVM argument or viaSystem.setProperty
).IBM has a pretty detailed post on how WebSphere handles DNS caching here. The relevant piece to the above is:
根据Oracle官方java属性,
sun.net.inetaddr.ttl
是 Sun 实现特定的属性,“未来版本可能不支持”。 “首选方法是使用安全属性”networkaddress.cache.ttl
。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
.所以我决定查看java源代码,因为我发现官方文档有点混乱。 我发现(对于 OpenJDK 11)大部分与其他人编写的内容一致。 重要的是属性的评估顺序。
InetAddressCachePolicy.java(为了便于阅读,我省略了一些样板文件):
您可以清楚地看到首先评估安全属性,然后评估系统属性,以及是否设置了其中任何一个
cachePolicy
值设置为该数字或-1 (FOREVER)
如果它们的值低于 -1。 如果未设置任何内容,则默认为 30 秒。 事实证明,OpenJDK 几乎总是如此,因为默认情况下 java.security 不设置该值,仅设置负值。顺便说一句,如果未设置 networkaddress.cache.male.ttl(从文件中删除),则 java 类内的默认值为 0。文档在这方面是错误的。 这就是让我绊倒的原因。
So I decided to look at the java source code because I found official docs a bit confusing. And what I found (for OpenJDK 11) mostly aligns with what others have written. What is important is the order of evaluation of properties.
InetAddressCachePolicy.java (I'm omitting some boilerplate for readability):
You can clearly see that the security property is evaluated first, system property second and if any of them is set
cachePolicy
value is set to that number or-1 (FOREVER)
if they hold a value that is bellow -1. If nothing is set it defaults to 30 seconds. As it turns out for OpenJDK that is almost always the case because by defaultjava.security
does not set that value, only a negative one.BTW if the
networkaddress.cache.negative.ttl
is not set (removed from the file) the default inside the java class is 0. Documentation is wrong in this regard. This is what tripped me over.我遇到过同样的问题。 默认情况下,JVM 会永久缓存 DNS 查找的结果。 将 networkaddress.cache.ttl 设置为 0 会有所帮助,但它不会“尊重”DNS 记录 TTL。
我使用了 https://github.com/dnsjava/dnsjava 库。
无论 networkaddress.cache.ttl 设置如何,这都会遵循 DNS 记录 TTL。
I had the same issue. By default JVM caches the results of DNS lookup forever. Setting networkaddress.cache.ttl to 0 helps, but it doesn't "honor" the DNS record TTL.
I used https://github.com/dnsjava/dnsjava library.
This does honor the DNS record TTL regardless of networkaddress.cache.ttl setting.