web-dev-qa-db-ja.com

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

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

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

87
ZZ Coder

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

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

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

64
Byron Whitlock

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

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

-Dsun.net.inetaddr.ttl=0

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

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

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

このコードmustは、JVMの他のコードがネットワーク操作を実行しようとする前に実行されます。

これは重要です。たとえば、.warファイルでSecurity.setPropertyを呼び出してその.warをTomcatにデプロイした場合、これは機能しません。TomcatはJavaネットワークスタックを使用しますこの「競合状態」のため、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スプーフィング攻撃 の影響を受けにくいと合理的に確信している場合にのみ、これを行ってください。

61
Les Hazlewood

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

バイロンの答えを拡張するには、ファイルを編集する必要があると思います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 file ここ

17
matt b

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

Java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");

これは、システムプロパティ-Dsun.net.inetaddr.ttlでも設定できますが、セキュリティプロパティが他の場所に設定されている場合、これは上書きされません。

また、WebSphereのWebサービスでこの問題が発生している場合は、networkaddress.cache.ttlを設定するだけでは十分ではないことを付け加えます。システムプロパティdisableWSAddressCachingtrueに設定する必要があります。有効期間プロパティとは異なり、これはJVM引数として、またはSystem.setPropertyを介して設定できます。

IBMには、WebSphereがDNSキャッシングを処理する方法に関するかなり詳細な投稿があります here 。上記に関連する部分は次のとおりです。

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

6
thesquaregroot

公式Oracle JavaプロパティSun.net.inetaddr.ttlはSun実装固有のプロパティであり、「将来のリリースではサポートされなくなる可能性があります」。 「望ましい方法は、セキュリティプロパティを使用することです」networkaddress.cache.ttl

1
CloudStax