Как заставить Java соблюдать время ожидания кэширования DNS? - PullRequest
86 голосов
/ 10 августа 2009

Мы используем GSLB для геораспределения и распределения нагрузки. Каждой услуге присваивается фиксированное доменное имя. С помощью некоторой магии DNS доменное имя преобразуется в IP-адрес, ближайший к серверу с наименьшей нагрузкой. Чтобы балансировка нагрузки работала, сервер приложений должен учитывать TTL из ответа DNS и снова разрешать доменное имя, когда тайм-аут кэша. Однако я не мог найти способ сделать это на Java.

Приложение на Java 5, работающее в Linux (Centos 5).

Ответы [ 6 ]

61 голосов
/ 10 августа 2009

Java имеет довольно странное поведение при кэшировании DNS. Лучше всего отключить кэширование DNS или установить для него меньшее число, например 5 секунд.

networkaddress.cache.ttl (по умолчанию: -1)
Указывает политику кэширования для успешного поиска имен из службы имен. Значение указывается как целое число, чтобы указать количество секунд для кэширования успешного поиска. Значение -1 означает «кэш навсегда».

networkaddress.cache.negative.ttl (по умолчанию: 10)
Указывает политику кэширования для неудачных поисков имен из службы имен. Значение указывается как целое число, чтобы указать количество секунд для кэширования сбоя при неудачных поисках. Значение 0 указывает «никогда не кэшировать». Значение -1 указывает «кэш навсегда».

60 голосов
/ 20 июня 2013

Согласно ответу Байрона, вы не можете установить networkaddress.cache.ttl или networkaddress.cache.negative.ttl в качестве системных свойств, используя флаг -D или вызывая System.setProperty, потому что это не системные свойства - они Безопасность свойства.

Если вы хотите использовать системное свойство для запуска этого поведения (чтобы вы могли использовать флаг -D или вызвать System.setProperty), вам нужно установить следующее свойство System :

-Dsun.net.inetaddr.ttl=0

Это системное свойство активирует желаемый эффект.

Но учтите: если вы не используете флаг -D при запуске процесса JVM и решите вместо этого вызывать его из кода:

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

Этот код должен выполняться до того, как любой другой код в JVM попытается выполнить сетевые операции.

Это важно, потому что, например, если вы вызвали Security.setProperty в файле .war и развернули этот файл .war в Tomcat, это не сработает: Tomcat использует сетевой стек Java для инициализации себя намного раньше, чем ваш. код войны выполнен. Из-за этого «состояния гонки» обычно более удобно использовать флаг -D при запуске процесса JVM.

Если вы не используете -Dsun.net.inetaddr.ttl=0 или не звоните Security.setProperty, вам нужно будет отредактировать $JRE_HOME/lib/security/java.security и установить эти свойства безопасности в этом файле, например,

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

Но обратите внимание на предупреждения безопасности в комментариях к этим свойствам. Делайте это только в том случае, если вы достаточно уверены, что не подвержены атакам спуфинга DNS .

21 голосов
/ 08 марта 2013

Это, очевидно, было исправлено в более новых версиях (SE 6 и 7). Максимальное время кэширования составляет 30 секунд при выполнении следующего фрагмента кода при просмотре активности порта 53 с использованием tcpdump.

/**
 * /1344137/kak-zastavit-java-soblydat-vremya-ozhidaniya-keshirovaniya-dns
 *
 * 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();
        }
    }
}
17 голосов
/ 10 августа 2009

Чтобы расширить ответ Байрона, я считаю, что вам нужно отредактировать файл 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 файлу здесь .

6 голосов
/ 04 июня 2015

Чтобы суммировать другие ответы, в <jre-path>/lib/security/java.security вы можете установить значение свойства networkaddress.cache.ttl, чтобы настроить кэширование DNS-запросов. Обратите внимание, что это не системное свойство, а свойство безопасности. Я смог установить это с помощью:

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

Это также может быть установлено системным свойством -Dsun.net.inetaddr.ttl, хотя это не будет переопределять свойство безопасности, если оно установлено в другом месте.

Я также хотел бы добавить, что если вы видите эту проблему с веб-сервисами в WebSphere, как я, настройка networkaddress.cache.ttl будет недостаточной. Вам необходимо установить системное свойство disableWSAddressCaching в true. В отличие от свойства времени жизни, оно может быть установлено в качестве аргумента JVM или через System.setProperty).

У IBM есть довольно подробный пост о том, как WebSphere обрабатывает DNS-кэширование здесь . Соответствующий кусок к вышесказанному:

Чтобы отключить кэширование адресов для веб-служб, необходимо установить для дополнительного настраиваемого свойства JVM disableWSAddressCaching значение true. Используйте это свойство, чтобы отключить кэширование адресов для веб-сервисов. Если ваша система обычно работает с большим количеством клиентских потоков, и вы столкнулись с конфликтом блокировок в кэше wsAddrCache, вы можете установить для этого пользовательского свойства значение true, чтобы предотвратить кэширование данных веб-служб.

1 голос
/ 08 октября 2017

В соответствии с официальными свойствами Java-оракула , sun.net.inetaddr.ttl - это свойство, зависящее от реализации Sun, которое "может не поддерживаться в будущих выпусках". «предпочтительным способом является использование свойства безопасности» networkaddress.cache.ttl.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...