У нас есть пакетное задание, которое выполняется каждый день на инстансе 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.
Я в недоумении, где искать источник проблемы. Кто-нибудь там испытал что-нибудь подобное?




Я думаю, что это не проблема, специфичная для 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) возвращают 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, так как он требует меньше усилий и сводит к минимуму возможные побочные эффекты. Итак, это решило проблему для меня.
Хорошие предложения, я не думал, что разрешение DNS для some.publicserver.com устаревает, что на самом деле может быть проблемой с их стороны. Я добавлю еще несколько журналов в пакетное задание, чтобы посмотреть, прольет ли оно свет.