Frage Gibt es eine Möglichkeit, Java das DNS Caching Timeout (TTL) zu verleihen?


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

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


75
2017-08-10 18:49


Ursprung


Antworten:


Java hat einige wirklich seltsame DNS Caching-Verhalten. Am besten schalten Sie die DNS-Zwischenspeicherung aus oder stellen Sie eine niedrige Zahl wie 5 Sekunden ein.

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

Netzwerkadress.cache.negative.ttl (Standard: 10)
    Gibt die Zwischenspeicherungsrichtlinie für nicht erfolgreiche Namensnachschlagevorgänge aus dem Name-Service an. Der Wert wird als Ganzzahl angegeben, um die Anzahl der Sekunden anzugeben, in denen der Fehler für nicht erfolgreiche Suchvorgänge zwischengespeichert werden soll. Ein Wert von 0 bedeutet "niemals cachen". Ein Wert von -1 bedeutet "Cache für immer".


55
2017-08-10 19:00



Per Byrons Antwort können Sie nicht einstellen networkaddress.cache.ttl oder networkaddress.cache.negative.ttl als Systemeigenschaften unter Verwendung der -D Flagge oder Berufung System.setProperty denn das sind keine Systemeigenschaften - sie sind es Sicherheit Eigenschaften.

Wenn Sie eine Systemeigenschaft verwenden möchten, um dieses Verhalten auszulösen (so können Sie die -D Flagge oder Anruf System.setProperty), möchten Sie Folgendes festlegen System Eigentum:

-Dsun.net.inetaddr.ttl=0

Diese Systemeigenschaft aktiviert den gewünschten Effekt.

Aber sei dir bewusst: wenn du das nicht benutzt -D Markieren Sie beim Starten des JVM-Prozesses und wählen Sie stattdessen, dass Sie diesen Code aufrufen:

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

Dieser Code Muss ausführen, bevor ein anderer Code in der JVM versucht, Netzwerkoperationen durchzuführen.

Dies ist wichtig, zum Beispiel, wenn Sie angerufen haben Security.setProperty In einer .war-Datei, die .war an Tomcat bereitgestellt wurde, funktionierte dies nicht: Tomcat verwendet den Java-Netzwerkstapel, um sich viel früher zu initialisieren, als der .war-Code ausgeführt wird. Wegen dieser "Race Condition" ist es normalerweise bequemer, die -D Flag beim Starten des JVM-Prozesses.

Wenn Sie nicht verwenden -Dsun.net.inetaddr.ttl=0 oder anrufen Security.setProperty, müssen Sie bearbeiten $JRE_HOME/lib/security/java.security und setze diese Sicherheitseigenschaften in dieser Datei, 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 einigermaßen sicher sind, dass Sie nicht anfällig dafür sind DNS-Spoofing-Angriffe.


44
2018-06-20 16:50



Dies wurde offensichtlich in neueren Versionen behoben (SE 6 und 7). Ich erlebe eine max. 30-sekündige Caching-Zeit beim Ausführen des folgenden Code-Snippets, während ich die Port 53-Aktivität mit tcpdump beobachte.

/**
 * 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();
        }
    }
}

19
2017-08-10 19:33



Um die Antwort von Byron zu erweitern, glaube ich, dass Sie die Datei bearbeiten müssen 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 über die java.security Datei Hier.


17
2018-06-03 21:12



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

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

Dies kann auch durch die Systemeigenschaft eingestellt werden -Dsun.net.inetaddr.ttl Allerdings wird dadurch eine Sicherheitseigenschaft nicht überschrieben, wenn sie an anderer Stelle festgelegt wird.

Ich möchte auch hinzufügen, dass, wenn Sie dieses Problem mit Web-Services in WebSphere sehen, wie ich war, Einstellung networkaddress.cache.ttl wird nicht genug sein. Sie müssen die Systemeigenschaft festlegen disableWSAddressCaching zu true. Im Gegensatz zur Time-to-Live-Eigenschaft kann dies als JVM-Argument oder via festgelegt werden System.setProperty).

IBM hat einen ziemlich detaillierten Beitrag darüber, wie WebSphere DNS-Caching handhabt Hier. Das relevante Stück zu dem oben genannten ist:

Um das Adresscaching für Webdienste zu deaktivieren, müssen Sie eine zusätzliche benutzerdefinierte JVM-Eigenschaft disableWSAddressCaching auf true festlegen. Verwenden Sie diese Eigenschaft, um das Adresscaching für Webdienste zu deaktivieren. Wenn Ihr System in der Regel mit vielen Client-Threads ausgeführt wird und im Konflikt mit dem Cache wsAddrCache Sperrenkonflikte auftreten, können Sie diese benutzerdefinierte Eigenschaft auf true festlegen, um das Zwischenspeichern der Web-Service-Daten zu verhindern.


4
2017-10-07 23:44



Entsprechend der Offizielle Oracle Java-Eigenschaften, sun.net.inetaddr.ttl ist eine Sun-Implementierungs-spezifische Eigenschaft, die in zukünftigen Releases möglicherweise nicht unterstützt wird. "Der bevorzugte Weg ist die Verwendung der Sicherheitseigenschaft" networkaddress.cache.ttl.


1