WEB-приложение Сведение отчетности  (13.12.2024)
Поддержка долгоживущих соединений между сервером приложений и сервером СУБД (Oracle или Postgres)

При длительном неиспользовании 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 сек

Важно!
Применять вышеуказанные настройки необходимо на серверной стороне СУБД, для того чтобы сразу охватить все клиентские соединения.