JavaにDNSキャッシュタイムアウトを尊重させる方法は?


100

地理分布と負荷分散にはGSLBを使用します。各サービスには固定ドメイン名が割り当てられています。いくつかのDNSマジックにより、ドメイン名は、負荷が最小のサーバーに最も近いIPに解決されます。負荷分散が機能するためには、アプリケーションサーバーはDNS応答からのTTLを尊重し、キャッシュがタイムアウトしたときにドメイン名を再度解決する必要があります。しかし、Javaでこれを行う方法を理解できませんでした。

アプリケーションはJava 5で、Linux(Centos 5)で実行されています。

回答:


76

バイロンの答えごとに、あなたが設定することはできませんnetworkaddress.cache.ttlまたはnetworkaddress.cache.negative.ttl使用することにより、システムのプロパティとして-Dフラグを呼び出すか、System.setPropertyこれらはシステムのプロパティではありませんので、 -それらはセキュリティのプロパティ。

システムプロパティを使用してこの動作をトリガーする(-Dフラグを使用するかを呼び出すことができるSystem.setProperty)場合は、次のシステムプロパティを設定する必要があります。

-Dsun.net.inetaddr.ttl=0

このシステムプロパティは、目的の効果を有効にします。

ただし、注意してください-D。JVMプロセスの開始時にフラグを使用せず、コードからこれを呼び出すことを選択した場合:

java.security.Security.setProperty("networkaddress.cache.ttl" , "0")

このコードは、JVMの他のコードがネットワーク操作を実行する前に実行する必要があります。

これは重要です。たとえば、Security.setProperty.warファイルを呼び出して.warをTomcatにデプロイした場合、これは機能しません。Tomcatは、.warのコードが実行されるよりもはるか前に、Javaネットワークスタックを使用して初期化します。この「競合状態」のため、通常-D、JVMプロセスを開始するときにフラグを使用する方が便利です。

を使用し-Dsun.net.inetaddr.ttl=0たり呼び出したりしない場合は、そのファイルのセキュリティプロパティSecurity.setPropertyを編集$JRE_HOME/lib/security/java.securityして設定する必要があります。たとえば、

networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0

ただし、これらのプロパティに関するコメントのセキュリティ警告に注意してください。DNSスプーフィング攻撃の影響を受けにくいと確信できる場合にのみ、これを行ってください。


2
FQNはjava.security.Security(少なくともjdk7では)
Pablo Fernandez

1
ただのコメントですが、これらのセキュリティ警告は、主にセキュリティマネージャーとリモート読み込みに関連しています。DNSをある程度まで信頼する通常のサーバーアプリケーションでは、TTLを減らしても問題ありません。(ただし、0は適切な最小値ではないと思いますが、ほとんどの場合、セキュリティマネージャー以外の場合はデフォルトの30秒で十分です)。
eckes

3
システムプロパティはOpenJDKでも機能しますか、それともOracle固有ですか?
mhlz 2016年

67

Javaには、非常に奇妙なDNSキャッシング動作があります。あなたの最善の策は、DNSキャッシングをオフにするか、5秒などの低い数値に設定することです。

networkaddress.cache.ttl(デフォルト:-1)
ネームサービスからの名前検索が成功した場合のキャッシュポリシーを示します。値は整数として指定され、成功したルックアップをキャッシュする秒数を示します。値-1は、「永久にキャッシュ」を示します。

networkaddress.cache.negative.ttl(デフォルト:10)
ネームサービスからの名前検索が失敗した場合のキャッシュポリシーを示します。値は整数として指定され、失敗したルックアップの失敗をキャッシュする秒数を示します。値0は、「キャッシュしない」を示します。値-1は、「永久にキャッシュ」を示します。


7
注:これにより、OSのすべてのDNSキャッシュが無効になるわけではありません。ライブラリ内のJava自体の壊れたメモリ内キャッシュを無効にするだけです。JVMを呼び出すときに、コマンドラインでこれらのプロパティを設定するだけです。
ネルソン

2
「壊れた」が有効であることを知りません。Javaは(セキュリティ上の理由から)DNSエントリを永久に、またはJVMが再起動されるまで、いずれか早い方でキャッシュします。これは(私が言えることから)仕様によるものです。設定は、java.securityポリシーファイルまたはコマンドラインで行うことができます。設定はそれぞれ異なります。リファレンス:rgagnon.com/javadetails/java-0445.html
Milner

4
これらはシステムプロパティではないため、システムプロパティとして設定することはできません(つまり、-DフラグまたはSystem.setPropertyを使用して)。これらはセキュリティプロパティです。
Les Hazlewood

6
このドキュメントは1.7では少し異なります。具体的には、セキュリティマネージャーが存在する場合にのみ永久にキャッシュが発生します。「デフォルトの動作では、セキュリティマネージャーがインストールされている場合は永久にキャッシュされ、セキュリティマネージャーがインストールされていない場合は実装固有の期間キャッシュされます。」 docs.oracle.com/javase/7/docs/technotes/guides/net/...
ブレットOkken

1
@Michael参照してくださいSystem.getSecurityManager()。Javaの8のためのドキュメント:docs.oracle.com/javase/8/docs/api/java/lang/...
gesellix

22

これは明らかに新しいリリース(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();
        }
    }
}

16
はい、Java 1.5のデフォルト値は無限キャッシングです。Java 1.6および1.7のデフォルトは30秒です。
Michael

7
1.7のドキュメントでは、これはセキュリティマネージャーが存在しない場合にのみ当てはまる可能性があることを示しています。マネージャーがインストールされていません。」 docs.oracle.com/javase/7/docs/technotes/guides/net/...
ブレットOkken

1
@Michaelはその情報のソースを共有することに気をつけていますか?
rustyx 2014年

4
@rustyx Oracleの1.6および1.7 JDKは、jre / lib / security / java.securityでnetworkaddress.cache.ttlに対してこれを持っています: "#デフォルト値は永久に(FOREVER)です。セキュリティーが設定されていない場合、デフォルトの動作は30秒間キャッシュすることです。」そのため、Java Web Startを介してデプロイされたアプレットおよびアプリは、引き続き永久にキャッシュします。それ以外の場合は30秒です。
マイケル

1
OpenJDK 8のjava.securityへのコードポインタは次のとおりです。これは、セキュリティマネージャがない場合、TTLは30 秒であることを示しています。hg.openjdk.java.net / jdk8u / jdk8u / jdk / file / f940e7a48b72 / src / share / 私はこれをMac OS XとUbuntu 14.04でテストしました。
tro

18

バイロンの答えを拡張するに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ファイルのドキュメントはこちら


5
これに追加するには、tomcat6を使用するときに、プログラムまたはJAVA_OPTS変数を介したnetworkaddress.cache.ttlまたはsun.net.inetaddr.ttlの設定が機能しなかったため、lib / securityファイルを変更する必要がありました。
11

1
@brampありがとう、私も同じ問題に直面しており、コメントと回答に+1を使用することで解決しました。
Bhavik Ambani、2015

7

他の回答を要約する<jre-path>/lib/security/java.securityと、プロパティの値を設定して、networkaddress.cache.ttlDNSルックアップのキャッシュ方法を調整できます。これはシステムプロパティではなくセキュリティプロパティであることに注意してください。私はこれを使ってこれを設定することができました:

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キャッシングをどのように処理するかについてかなり詳細な投稿をしています。上記に関連する部分は次のとおりです。

Webサービスのアドレスキャッシングを無効にするには、追加のJVMカスタムプロパティdisableWSAddressCachingをtrueに設定する必要があります。このプロパティを使用して、Webサービスのアドレスキャッシュを無効にします。通常、システムが多数のクライアントスレッドで実行されているときにwsAddrCacheキャッシュでロックの競合が発生した場合は、このカスタムプロパティをtrueに設定して、Webサービスデータのキャッシュを回避できます。


2

公式のoracle javaプロパティによると、sun.net.inetaddr.ttlSunの実装固有のプロパティであり、「将来のリリースではサポートされなくなる可能性があります」。「推奨される方法は、セキュリティプロパティを使用することnetworkaddress.cache.ttlです」。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.