Спорадические проблемы с разрешением DNS в http-клиенте Java

У нас есть пакетное задание, которое выполняется каждый день на инстансе EC2 в AWS. Экземпляр EC2 существует в VPC. Пакетное задание использует Java для выполнения серии вызовов REST API на общедоступном сервере. В большинстве дней пакетное задание выполняется без проблем. Однако в некоторые дни что-то ломается в разрешении DNS. Задание будет успешно выполняться, а затем внезапно произойдет сбой разрешения DNS, и оставшийся API вызовет ошибку с исключением, подобным следующему:

java.net.UnknownHostException: some.publicserver.com: Name or service not known
  at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) ~[na:1.8.0_191]
  at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:929) ~[na:1.8.0_191]
  at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1324) ~[na:1.8.0_191]
  at java.net.InetAddress.getAllByName0(InetAddress.java:1277) ~[na:1.8.0_191]
  at java.net.InetAddress.getAllByName(InetAddress.java:1193) ~[na:1.8.0_191]
  at java.net.InetAddress.getAllByName(InetAddress.java:1127) ~[na:1.8.0_191]
  at org.apache.http.impl.conn.SystemDefaultDnsResolver.resolve(SystemDefaultDnsResolver.java:44) ~[batchjob.jar:na]
  at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:102) ~[batchjob.jar:na]
  at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319) ~[batchjob.jar:na]
  at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363) ~[batchjob.jar:na]
  at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219) ~[batchjob.jar:na]
  at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) ~[batchjob.jar:na]
  at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) ~[batchjob.jar:na]
  at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) ~[batchjob.jar:na]
  at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) ~[batchjob.jar:na]
  at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) ~[batchjob.jar:na]
  at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) ~[batchjob.jar:na]
  ...

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

nslookup some.publicserver.com

Он возвращает успешный ответ. В то же время пакетное задание будет извергать кучу исключений UnknownHostException.

Я в недоумении, где искать источник проблемы. Кто-нибудь там испытал что-нибудь подобное?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
1 857
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я думаю, что это не проблема, специфичная для Java, а проблема разрешения DNS с экземпляром EC2. Java будет эффективно выполнять действия по разрешению DNS, сначала проверяя файл hosts, а затем вызывая функции, связанные с DNS базовой ОС.

Имея это в виду, а также тот факт, что на базовом экземпляре EC2 фактически работает дистрибутив Linux, эти шаги приведут к вызову функции gethostbyname2 ОС. Это, в свою очередь, выполнит всю скрытую магию для разрешения рассматриваемого имени.

Теперь две вещи очень важны при устранении неполадок. Во-первых, часто ли меняется IP-адрес сервера, на который вы звоните. Во-вторых, используемая вами программа nslookup будет напрямую запрашивать DNS-сервер. Это означает, что вполне могут быть несоответствия между тем, что Java пытается сделать для разрешения доменного имени, и тем, что делает программа. Кроме того, это также может означать, что ОС могла кэшировать IP-адрес, который не соответствует последнему адресу сервера. Таким образом, я бы предложил проверить IP-адрес имени хоста с помощью какой-либо другой утилиты (например, ping).

Мои лучшие советы по устранению неполадок будут следующими:

  • Добавление некоторой трассировки журнала при попытке выполнить имя хоста разрешение и сравнение его с разрешенным значением nslookup.

  • Проверка правильности настройки DNS в EC2 (какой DNS-сервер вы используете и т. д.).

  • Добавление записи в файл hosts, сопоставляющей доменное имя с IP-адресом адрес (при условии, что последний не меняется).

Надеюсь, вышеизложенное поможет.

Хорошие предложения, я не думал, что разрешение DNS для some.publicserver.com устаревает, что на самом деле может быть проблемой с их стороны. Я добавлю еще несколько журналов в пакетное задание, чтобы посмотреть, прольет ли оно свет.

Mike 05.02.2019 17:47

Для чего это стоит, в моей конкретной ситуации, вот что я смог выяснить. Надеюсь, это поможет кому-то еще в будущем.

Полномочные DNS-серверы для цели в моем примере (some.publicserver.com) возвращают SERVFAIL для некоторых запросов. Скорее всего, это проблема с нагрузкой, поскольку это происходит время от времени в течение дня. В моей настройке AWS я использую DNS-серверы по умолчанию для своего VPC, которые предоставляются AWS. Эти серверы, по-видимому, не кэшируют. Я узнал, что Java выполняет некоторое кэширование для разрешений DNS через InetAddress, но по умолчанию это короткое окно (я полагаю, 30 секунд в большинстве реализаций).

Итак, в конце концов, настоящая причина проблемы заключается в том, что авторитетные DNS-серверы для some.publicserver.com не являются полностью надежными. Поскольку у меня нет контроля над этими серверами, я думаю, что лучший обходной путь — использовать кэширование DNS. Вариант №1 — использовать локальное кеширование DNS на моем экземпляре EC2 Ubuntu (что-то вроде dnsmasq). Вариант № 2 — увеличить продолжительность кэширования, используемого Java, выполнив что-то вроде этого:

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

Я выбрал вариант № 2, так как он требует меньше усилий и сводит к минимуму возможные побочные эффекты. Итак, это решило проблему для меня.

Другие вопросы по теме