web-dev-qa-db-fra.com

Comment faire Java respecter le délai de mise en cache du DNS?

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 charge fonctionne, le serveur d'applications doit respecter la réponse DNS du TTL) et résoudre le nom de domaine une fois le délai d'expiration du cache expiré. Cependant, je n'ai pas trouvé de solution. faire cela en Java.

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

87
ZZ Coder

Java a un comportement de mise en cache DNS particulièrement étrange. Votre meilleur pari est de désactiver la mise en cache DNS ou de le définir sur un nombre peu élevé, comme 5 secondes.

networkaddress.cache.ttl (par défaut: -1)
Indique la stratégie de mise en cache pour les recherches de noms effectuées avec succès par le service de noms. La valeur est spécifiée sous la forme d'un entier pour indiquer le nombre de secondes pendant lesquelles la recherche a été mise en cache. Une valeur de -1 indique "cache pour toujours".

networkaddress.cache.negative.ttl (valeur par défaut: 10)
Indique la stratégie de mise en cache pour les recherches de noms infructueuses à partir du service de noms. La valeur est spécifiée sous la forme d'un entier pour indiquer le nombre de secondes pendant lesquelles la défaillance en mémoire cache pour les recherches infructueuses. Une valeur de 0 indique "ne jamais mettre en cache". Une valeur de -1 indique "cache pour toujours".

64
Byron Whitlock

Selon la réponse de Byron, vous ne pouvez pas définir networkaddress.cache.ttl Ou networkaddress.cache.negative.ttl Comme propriétés système en utilisant l'indicateur -D Ou en appelant System.setProperty, Car il ne s'agit pas de propriétés système - ce sont des propriétés Security .

Si vous souhaitez utiliser une propriété System pour déclencher ce comportement (vous pouvez donc utiliser l'indicateur -D Ou appeler System.setProperty), Vous souhaiterez définir ce qui suit Propriété System :

-Dsun.net.inetaddr.ttl=0

Cette propriété système activera l'effet souhaité.

Sachez toutefois que si vous n'utilisez pas l'indicateur -D Lors du démarrage du processus JVM, choisissez de l'appeler à partir du code:

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

Ce code doit s'exécuter avant tout autre code de la machine virtuelle Java tentant d'effectuer des opérations de mise en réseau.

Ceci est important car, par exemple, si vous appeliez Security.setProperty Dans un fichier .war et déployiez ce fichier .war sur Tomcat, cela ne fonctionnerait pas: Tomcat utilise le Java réseau stack pour s’initialiser bien plus tôt que le code de votre .war n’est exécuté. En raison de cette "condition de concurrence", il est généralement plus pratique d’utiliser l’indicateur -D lors du démarrage du processus JVM.

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éfinir les propriétés de sécurité de ce fichier, par exemple.

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

Mais faites attention aux avertissements de sécurité dans les commentaires entourant ces propriétés. Ne le faites que si vous êtes raisonnablement confiant que vous n’êtes pas susceptible de attaques par usurpation de DNS .

61
Les Hazlewood

Ceci a évidemment été corrigé dans les versions les plus récentes (SE 6 et 7). Le temps de mise en cache est limité à 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();
        }
    }
}
21
user1050755

Pour développer la réponse de Byron, je pense que vous devez modifier le fichier Java.security dans le %JRE_HOME%\lib\security répertoire 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 Java.security fichier ici .

17
matt b

Pour résumer les autres réponses, in <jre-path>/lib/security/Java.security vous pouvez définir la valeur de la propriété networkaddress.cache.ttl pour ajuster la mise en cache des recherches DNS. Notez que ceci n'est pas une propriété système mais une propriété de sécurité. J'ai pu régler ceci en utilisant:

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

Ceci peut également être défini par la propriété système -Dsun.net.inetaddr.ttl bien que cela ne remplace pas une propriété de sécurité si elle est définie ailleurs.

J'aimerais également ajouter que si vous rencontrez ce problème avec les services Web dans WebSphere, comme je l'étais, la définition de networkaddress.cache.ttl ne suffira pas. Vous devez définir la propriété système disableWSAddressCaching sur true. Contrairement à la propriété time-to-live, elle peut être définie en tant qu'argument JVM ou via System.setProperty).

IBM a publié un article assez détaillé sur la manière dont WebSphere gère la mise en cache DNS here . La pièce pertinente à ce qui précède est:

Pour désactiver la mise en cache des adresses pour les services Web, vous devez définir une propriété supplémentaire de la machine virtuelle Java, disableWSAddressCaching, sur true. Utilisez cette propriété pour désactiver la mise en cache des adresses pour les services Web. Si votre système s'exécute généralement avec un grand nombre de threads client et que vous rencontrez des conflits de verrouillage sur le cache wsAddrCache, vous pouvez définir cette propriété personnalisée sur true afin d'empêcher la mise en cache des données des services Web.

6
thesquaregroot

Selon le Oracle officiel Java) , Sun.net.inetaddr.ttl est la propriété spécifique à l’implémentation de Sun, qui "pourrait ne pas être prise en charge dans les versions ultérieures". "le moyen préféré consiste à utiliser la propriété de sécurité" networkaddress.cache.ttl.

1
CloudStax