Установите TTL для данных DNS для Amazon Aurora

Мы используем Amazon Aurora (PostgreSQL) и получаем периодические ошибки при попытке подключения к базе данных:

System.Net.Sockets.SocketException (0x80004005): This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server.

Но и:

System.Exception: An error occurred while updating the entries. See the inner exception for details. ---> System.Exception: An error occured while retrieving the InformationSchemaTable information. See the inner exception for details. ---> System.Net.Sockets.SocketException: This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server

Мы используем npgsql 3.2.5. Мы периодически получаем такие ошибки как с выделенного сервера под управлением Windows Server 2016, так и с кода, размещенного в службе приложений Azure. Сотни подключений выполняются успешно, но некоторые (несколько в час) завершаются с ошибками, подобными этим. При их возникновении нет существенной нагрузки на базу данных, а не аномального количества подключений (далеко от предела).

Я нашел это в Amazon Aurora Best Practices:

Если ваше клиентское приложение кэширует данные службы доменных имен (DNS) ваших экземпляров БД, установите значение времени жизни (TTL) менее 30 секунд. Поскольку базовый IP-адрес экземпляра БД может измениться после отработки отказа, кэширование данных DNS в течение длительного времени может привести к сбоям подключения, если ваше приложение попытается подключиться к IP-адресу, который больше не используется.

Итак, мой вопрос: как узнать, кэширует ли мое клиентское приложение данные DNS? И есть ли способ установить TTL для запросов, сделанных Npgsql, или его нужно установить где-то в .NET или на сервере?

Изменить

Итак, после ответа Шейса я еще раз взглянул на него. Похоже, мы получаем два разных вида ошибок, в зависимости от среды хостинга.

Наш код, размещенный на выделенном сервере, получает следующие ошибки (DNS):

System.Data.Entity.Core.ProviderIncompatibleException: An error occurred while getting provider information from the database. This can be caused by Entity Framework using an incorrect connection string. Check the inner exceptions for details and ensure that the connection string is correct. ---> System.Data.Entity.Core.ProviderIncompatibleException: The provider did not return a ProviderManifestToken string. ---> System.Net.Sockets.SocketException: This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server
   at System.Net.Dns.GetAddrInfo(String name)
   at System.Net.Dns.InternalGetHostByName(String hostName, Boolean includeIPv6)
   at System.Net.Dns.GetHostAddresses(String hostNameOrAddress)
   at Npgsql.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
   at Npgsql.NpgsqlConnector.<RawOpen>d__139.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlConnector.<Open>d__136.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlConnection.<Open>d__28.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlConnection.Open()
   at Npgsql.NpgsqlServices.UsingPostgresDBConnection(NpgsqlConnection connection, Action`1 action)
   at Npgsql.NpgsqlServices.GetDbProviderManifestToken(DbConnection connection)
   at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   --- End of inner exception stack trace ---
   at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
   at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
...

Тот же код, размещенный в службах приложений Azure, получает следующую ошибку (подключения):

System.InvalidOperationException: An exception has been raised that is likely due to a transient failure. ---> Npgsql.NpgsqlException: Exception while reading from stream ---> System.IO.IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
   at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
   --- End of inner exception stack trace ---
   at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Npgsql.ReadBuffer.<Ensure>d__27.MoveNext()
   --- End of inner exception stack trace ---
   at Npgsql.ReadBuffer.<Ensure>d__27.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Npgsql.NpgsqlConnector.<DoReadMessage>d__148.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Npgsql.NpgsqlConnector.<ReadPrependedMessages>d__150.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlConnector.<ReadMessage>d__147.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlConnector.<ReadExpecting>d__154`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Npgsql.NpgsqlDataReader.<NextResult>d__32.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlDataReader.<<NextResultAsync>b__31_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlCommand.<Execute>d__71.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlCommand.<ExecuteDbDataReader>d__92.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Npgsql.NpgsqlCommand.<>c__DisplayClass90_0.<<ExecuteDbDataReaderAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<BufferlessMoveNext>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Storage.Internal.NpgsqlExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Storage.Internal.NpgsqlExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.<MoveNext>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.<FirstOrDefault_>d__165`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.TaskResultAsyncEnumerable`1.Enumerator.<MoveNext>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.SelectEnumerableAsyncIterator`2.<MoveNextCore>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Linq.AsyncEnumerable.AsyncIterator`1.<MoveNext>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.<MoveNext>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<ExecuteSingletonAsyncQuery>d__21`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at OpenIddict.OpenIddictProvider`4.<HandleTokenRequest>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler.<InvokeTokenEndpointAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerHandler.<HandleRequestAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.<Invoke>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.<Invoke>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequests>d__188`1.MoveNext()

Так что возможно это две проблемы, которые появились одновременно. Проблема Azure (проблема с подключением) стала появляться чаще после того, как мы убрали Keepalive=30 из строки подключения, возможно, стоит вернуть это.

Второй проблемой могут быть проблемы с подключением между нашим поставщиком серверов и DNS-сервером?

Обе проблемы носят периодический характер и возникают лишь несколько раз из сотен подключений.


person Joel    schedule 15.01.2019    source источник


Ответы (1)


Npgsql никаким образом не кэширует ответы DNS — он вызывает Dns.GetHostAddresses() (или Dns.GetHostAddressesAsync()) при каждой попытке физического подключения. Операционная система обычно кэширует, но на основе ответа, который она получает от DNS-сервера.

Однако сообщение об ошибке, которое вы видите, кажется, говорит об обратном — кажется, оно указывает на то, что вы пытались выполнить поиск DNS, но истекло время ожидания, то есть полномочный DNS-сервер не ответил в течение отведенного времени. Скорее всего, это какая-то проблема с сетевым подключением между вашим сервером и авторитетным DNS-сервером...

person Shay Rojansky    schedule 15.01.2019
comment
Хорошо, спасибо за разъяснение! Мы получаем больше этих ошибок, так как мы удалили Keepalive=30 из строки подключения. Как вы думаете, это может иметь какое-то отношение к этому? Дело в том, что мы получаем ошибки подключения как от выделенного сервера, так и от службы приложений Azure. Служба поддержки Amazon утверждает, что с их стороны проблем нет. - person Joel; 16.01.2019
comment
Keepalive действительно не должен быть связан ни с чем здесь... Он просто указывает Npgsql отправлять SELECT NULL каждые 30 секунд после простоя соединения - ничего общего с первоначальной попыткой физического подключения, в которой происходит разрешение DNS... I' м извините, я больше ничем не могу помочь, но это похоже на какую-то неясную проблему с сетью/DNS... - person Shay Rojansky; 16.01.2019
comment
Обратите внимание, что второе исключение, которое вы опубликовали, не связано с DNS, а просто является общим тайм-аутом при ожидании результатов запроса. Вы можете посмотреть, что происходит с запросом в PostgreSQL, пока ваш клиент ожидает ответа (например, обратившись к pg_stat_activity). Это может быть либо очень медленный запрос, либо проблема с сетью. - person Shay Rojansky; 16.01.2019
comment
Хм хорошо. Хотя это странно. Второе исключение исчезло после возвращения Keepalive=30 в строку подключения, никаких других изменений не было. А разве это не ошибка подключения? Вот как я интерпретирую ошибку, что это не тайм-аут при ожидании запроса. Но я думаю, вам виднее :) - person Joel; 16.01.2019
comment
Я помню, как где-то читал комментарий о том, что облачные провайдеры, такие как Azure, могут закрывать соединения, которые простаивают в течение длительного периода времени (что приведет к ошибке, когда это соединение будет взято из пула). Но, возможно, это выдаст еще одну ошибку. - person Joel; 16.01.2019
comment
Это правда - и это именно то, что должен предотвратить keepalive. Однако, насколько я понимаю, это не имеет ничего общего с проблемой DNS. - person Shay Rojansky; 16.01.2019
comment
Нет, я думаю, это было просто совпадение двух ошибок, появившихся одновременно. Но я думаю, что проблемы с DNS могут быть связаны с локальным сервером (не Azure). - person Joel; 16.01.2019