При длительном неиспользовании TCP соединения, роутеры между этими серверами могут начать оптимизировать использование своих ресурсов. Для этого они будут закрывать соединения, которые долго простаивали, обычно порогом является 2 ч. При этом ни сервер приложений, ни сервер СУБД не уведомляются о том, что их соединение оборвалось, и по-прежнему считают его активным.
Результат подобных обрывов соединений является нежелательным ни для сервера приложений, ни для сервера СУБД и будут приводить к многочисленным проблемам, например:
- при необходимости воспользоваться соединением, вызывающая сторона не сразу узнает, что соединение уже неактивно, и будет выжидать таймаут, особенно длительный в ОС Linux (около 15 мин. - см. параметр tcp_retries2)
- когда сервер приложений поймет, что соединение неактивно, то будет установлено новое соединение, но все данные сброшенного соединения будут потеряны:
- все активные транзакции текущего соединения, начавшиеся, но еще не завершенные, будут отменены. А это значит, что все выполненные, но еще не подтвержденные действия будут отменены. А также, при последующих запросах клиента в рамках текущей транзакции, он получит ошибку, и будет вынужден выполнять запрос заново.
- недофетченные селективные запросы сброшены, как на стороне СУБД, так и на стороне сервера приложений. А это значит, что при запросе клиента следующей порции данных из длительных селективных запросов, которые клиент еще не дофетчил до конца, он получит ошибку, и будет вынужден выполнять запрос заново.
Для того чтобы избежать подобных нежелательных обрывов соединений, предлагается ряд административных мер по настройке сервера СУБД для поддержания соединений в активном состоянии.
Проверка и поддержание соединения активным осуществляется следующим образом.
На серверной стороне СУБД, по истечению какого-то времени, клиенту посылаются специальные пакеты определенное количество раз. Как только клиент ответит на эти пакеты проверки соединения, то сервер признает это соединение живым и останавливает этот механизм на определенное время, через которое проверка осуществляется снова. Если клиент не отвечает на проверочные пакеты, то сервер отправляет эти пакеты в течение определенного времени, а затем, если ответ так и не поступил, признает соединение разорванным и закрывает его со своей серверной стороны.
В результате пересылки таких пакетов на простаивающих соединениях будет создаваться трафик и промежуточные роутеры будут считать, что соединение необходимо и еще используется, и не будут обрывать соединения, со своей стороны.
В Oracle, начиная с 12-й версии для этой механики используется настройки TCP соединений, которые хорошо описаны в следующей документации Oracle - Dead connection detection:
- TCP_KEEPIDDLE - время простоя соединения после которого начинаются попытки проверки соединения (отправка спец. пакетов). Значение берется из параметра SQLNET.EXPIRE_TIME, умолчательное значение 0, измеряется в минутах.
- TCP_KEEPCNT - количество попыток проверки соединения (отправка спец. пакетов). Зафиксированное значение (нельзя задать вручную) в Oracle - 10 раз.
- TCP_KEEPINTVL - интервал времени между попытками проверки соединения (отправка спец. пакетов). Зафиксированное значение (нельзя задать вручную) в Oracle - 6 сек.
Таким образом, в Oracle всем этим можно управлять только через настройку SQLNET.EXPIRE_TIME. Умолчательное значение 0, т.е. выключено. Для случаев когда необходимо включить механику поддержки активности соединений, рекомендуемое значение 10 минут.
В Postgres, (в 9.6 эти настройки точно уже присутствуют) есть аналогичные настройки в файле postgres.conf:
- tcp_keepalives_idle - измеряется в секундах. Умолчательное значение 0, в таком случае используется системное значение, которое в Linux и в Windows равняется 2-м часам.
- tcp_keepalives_count - умолчательное значение 0, в таком берется системное значение, которое в Linux равняется 9 раз
- tcp_keepalives_interval - измеряется в секундах. Умолчательное значение 0, в таком берется системное значение, которое в Linux равняется 75 сек.
Таким образом, в Postgres всем этим можно управлять через вышеуказанные настройки в файле конфигурации postgres.conf. Для случаев, когда необходимо включить механику поддержки активности соединений, рекомендуется начать со значений, применяемых Oracle, т.к. они более продуманные и приближенные к жизни, а именно:
- tcp_keepalives_idle - 600 сек, т.е. как и в SQLNET.EXPIRE_TIME, рекомендуется 10 мин
- tcp_keepalives_count - 10 раз
- tcp_keepalives_interval - 6 сек
Важно! | Применять вышеуказанные настройки необходимо на серверной стороне СУБД, для того чтобы сразу охватить все клиентские соединения. |