web-dev-qa-db-de.com

Wie kann man Java das DNS Caching Timeout einhalten?

Wir verwenden GSLB für die Geoverteilung und den Lastenausgleich. Jedem Dienst wird ein fester Domainname zugewiesen. Durch etwas DNS-Magie wird der Domänenname in eine IP-Adresse aufgelöst, die dem Server mit der geringsten Auslastung am nächsten liegt. Damit der Lastenausgleich funktioniert, muss der Anwendungsserver die TTL von der DNS-Antwort berücksichtigen und den Domänennamen erneut auflösen, wenn die Cache-Zeit abgelaufen ist. Ich konnte jedoch keinen Weg finden dies in Java zu tun.

Die Anwendung ist in Java 5, läuft unter Linux (Centos 5).

87
ZZ Coder

Java hat einige ernsthaft seltsame DNS-Caching-Verhalten. Ihre beste Wette ist es, das DNS-Caching auszuschalten oder auf eine niedrige Zahl wie 5 Sekunden einzustellen.

networkaddress.cache.ttl (Standard: -1)
Gibt die Caching-Richtlinie für erfolgreiche Namenssuchen vom Namensdienst an. Der Wert wird als Ganzzahl angegeben, um die Anzahl der Sekunden anzugeben, in denen die erfolgreiche Suche zwischengespeichert werden soll. Der Wert -1 gibt "Cache für immer" an.

networkaddress.cache.negative.ttl (Standard: 10)
Gibt die Caching-Richtlinie für nicht erfolgreiche Namenssuchen vom Namensdienst an. Der Wert wird als Ganzzahl angegeben, um die Anzahl der Sekunden anzugeben, in denen der Fehler für nicht erfolgreiche Suchvorgänge zwischengespeichert wird. Ein Wert von 0 gibt an, dass "nie zwischengespeichert wird". Der Wert -1 gibt "Cache für immer" an.

64
Byron Whitlock

Laut Byron können Sie networkaddress.cache.ttl Oder networkaddress.cache.negative.ttl Nicht als Systemeigenschaften festlegen, indem Sie das Flag -D Verwenden oder System.setProperty Aufrufen, da dies keine Systemeigenschaften sind. es sind Sicherheitseigenschaften .

Wenn Sie eine System-Eigenschaft verwenden möchten, um dieses Verhalten auszulösen (sodass Sie das -D - Flag verwenden oder System.setProperty Aufrufen können), möchten Sie Folgendes festlegen System Eigenschaft:

-Dsun.net.inetaddr.ttl=0

Diese Systemeigenschaft aktiviert den gewünschten Effekt.

Beachten Sie jedoch Folgendes: Wenn Sie beim Starten des JVM-Prozesses nicht das Flag -D Verwenden und dies stattdessen über den Code aufrufen:

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

Dieser Code muss ausgeführt werden, bevor ein anderer Code in der JVM versucht, Netzwerkoperationen auszuführen.

Dies ist wichtig, da dies beispielsweise nicht funktioniert, wenn Sie Security.setProperty In einer WAR-Datei aufgerufen und diese WAR-Datei für Tomcat bereitgestellt haben: Tomcat verwendet das Java Netzwerk Stack, um sich viel früher zu initialisieren, als der .war-Code ausgeführt wird. Aufgrund dieser "Race-Bedingung" ist es normalerweise bequemer, beim Starten des JVM-Prozesses das Flag -D zu verwenden.

Wenn Sie nicht -Dsun.net.inetaddr.ttl=0 Verwenden oder Security.setProperty Aufrufen, müssen Sie $JRE_HOME/lib/security/Java.security Bearbeiten und diese Sicherheitseigenschaften in dieser Datei festlegen, z.

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

Beachten Sie jedoch die Sicherheitswarnungen in den Kommentaren zu diesen Eigenschaften. Tun Sie dies nur, wenn Sie sicher sind, dass Sie nicht für DNS-Spoofing-Angriffe anfällig sind .

61
Les Hazlewood

Dies wurde offensichtlich in neueren Releases (SE 6 und 7) behoben. Ich erlebe eine maximale Caching-Zeit von 30 Sekunden, wenn der folgende Codeausschnitt ausgeführt wird, während die Aktivität von Port 53 mit tcpdump überwacht wird.

/**
 * 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

Um Byrons Antwort zu erweitern, müssen Sie meines Erachtens die Datei Java.security in dem %JRE_HOME%\lib\security Verzeichnis, um diese Änderung zu bewirken.

Hier ist der relevante Abschnitt:

#
# 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 

Dokumentation zum Java.security Datei hier .

17
matt b

Um die anderen Antworten zusammenzufassen, können Sie in <jre-path>/lib/security/Java.security Den Wert der Eigenschaft networkaddress.cache.ttl Festlegen, um anzupassen, wie DNS-Lookups zwischengespeichert werden. Beachten Sie, dass dies nicht eine Systemeigenschaft, aber eine Sicherheitseigenschaft ist. Ich konnte dies einstellen mit:

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

Dies kann auch durch die Systemeigenschaft -Dsun.net.inetaddr.ttl Festgelegt werden, obwohl dies eine Sicherheitseigenschaft nicht überschreibt, wenn sie an anderer Stelle festgelegt ist.

Ich möchte auch hinzufügen, dass das Festlegen von networkaddress.cache.ttl Nicht ausreicht, wenn dieses Problem bei Webdiensten in WebSphere auftritt. Sie müssen die Systemeigenschaft disableWSAddressCaching auf true setzen. Im Gegensatz zur Time-to-Live-Eigenschaft kann dies als JVM-Argument oder über System.setProperty) Festgelegt werden.

IBM hat einen ziemlich detaillierten Beitrag darüber verfasst, wie WebSphere mit DNS-Caching umgeht hier . Das relevante Stück zum oben genannten ist:

Um die Adresszwischenspeicherung für Webdienste zu deaktivieren, müssen Sie eine zusätzliche benutzerdefinierte JVM-Eigenschaft disableWSAddressCaching auf true festlegen. Verwenden Sie diese Eigenschaft, um die Adresszwischenspeicherung für Webdienste zu deaktivieren. Wenn Ihr System normalerweise mit vielen Client-Threads ausgeführt wird und im wsAddrCache-Cache Sperrenkonflikte auftreten, können Sie diese benutzerdefinierte Eigenschaft auf true setzen, um das Zwischenspeichern der Webdienstdaten zu verhindern.

6
thesquaregroot

Entsprechend den offiziellen Oracle Java Eigenschaften , Sun.net.inetaddr.ttl ist eine implementierungsspezifische Eigenschaft von Sun, die in zukünftigen Versionen möglicherweise nicht unterstützt wird. "Die bevorzugte Methode ist die Verwendung der Sicherheitseigenschaft" networkaddress.cache.ttl.

1
CloudStax