123 votes

Un moyen de faire en sorte que Java respecte le délai de mise en cache DNS (TTL)?

Nous utilisons GSLB pour la géo-distribution et l'équilibrage de charge. Chaque service se voit attribuer un nom de domaine fixe. Grâce à la magie du DNS, le nom de domaine est résolu en une adresse IP la plus proche du serveur avec le moins de charge. Pour que l'équilibrage de la charge fonctionne, le serveur d'applications doit respecter la réponse TTL à partir de la réponse DNS et résoudre à nouveau le nom de domaine lorsque le cache expire. Cependant, je ne pouvais pas trouver un moyen de faire cela en Java.

L'application est en Java 5, fonctionnant sous Linux (Centos 5).

97voto

Les Hazlewood Points 5336

Par Byron réponse, vous ne pouvez pas définir d' networkaddress.cache.ttl ou networkaddress.cache.negative.ttl que les Propriétés du Système à l'aide de la -D drapeau ou en appelant System.setProperty parce que ce ne sont pas des propriétés du Système - ils sont la Sécurité des propriétés.

Si vous souhaitez utiliser un Système de propriété pour déclencher ce comportement, de sorte que vous pouvez utiliser l' -D drapeau ou appelez - System.setProperty), vous pouvez définir les éléments suivants du Système de la propriété:

-Dsun.net.inetaddr.ttl=0

Ce système de propriété permettra à l'effet désiré.

Mais attention: si vous n'utilisez pas l' -D drapeau lors du démarrage de la JVM processus et choisir d'appeler ce code à la place:

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

Ce code doit s'exécuter avant toute autre code dans la JVM tentatives pour effectuer des opérations réseau.

Ceci est important parce que, par exemple, si vous appelez Security.setProperty dans une .la guerre de fichier et déployés .la guerre de Tomcat, ce ne serait pas le travail: Tomcat utilise le Java pile de réseau pour initialiser beaucoup plus tôt que votre .la guerre de code est exécuté. En raison de cette "race condition", il est souvent plus pratique d'utiliser l' -D drapeau lors du démarrage de la JVM processus.

Si vous n'utilisez pas -Dsun.net.inetaddr.ttl=0 ou appelez - Security.setProperty, vous devrez éditer $JRE_HOME/lib/security/java.security et définissez les propriétés de sécurité dans ce fichier, par exemple

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

Mais attention aux avertissements de sécurité dans les commentaires relatifs à ces propriétés. Faire cela seulement si vous êtes assez confiant que vous ne sont pas sensibles à l'usurpation DNS attaques.

77voto

Byron Whitlock Points 29863

Java a une sérieusement bizarre dns comportement de mise en cache. Votre meilleur pari est de désactiver la mise en cache dns ou à faible nombre comme les 5 secondes.

networkaddress.le cache.ttl (par défaut: -1)
Indique la politique de mise en cache pour le succès des recherches de noms du nom de service. La valeur est spécifiée en tant que nombre entier pour indiquer le nombre de secondes à cache le succès de la recherche. Une valeur de -1 indique que "cache à jamais".

networkaddress.le cache.négatif.ttl (par défaut: 10)
Indique la politique de mise en cache pour un nom de réussite des recherches à partir du nom du service. La valeur est spécifiée en tant que nombre entier pour indiquer le nombre de secondes à cache l'échec de l'onu-requêtes réussies. Une valeur de 0 indique "cache". Une valeur de -1 indique que "cache à jamais".

22voto

user1050755 Points 1165

Ceci a évidemment été corrigé dans les versions les plus récentes (SE 6 et 7). J'expérimente un délai de mise en cache maximal de 30 secondes lors de l'exécution de l'extrait de code suivant tout en surveillant l'activité du port 53 à l'aide de tcpdump.

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

19voto

matt b Points 73770

Pour approfondir la réponse de Byron, je pense que vous devez modifier le fichier java.security dans le répertoire %JRE_HOME%\lib\security pour effectuer ce changement.

Voici la section pertinente:

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

Documentation sur le fichier java.security ici .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X