Использование KEEPALIVE-сокетов для обнаружения и отключения зависших клиентских соединений InterBase и Firebird

Овчинников Василий, 17.05.2005, изменено – 06.09.2005.
 

Введение

В системах, предназначенных для работы в реальном времени или близком к нему, существует проблема отслеживания на серверной стороне состояния клиентских соединений и принятия мер для их принудительного отключения в случае недоступности клиента вследствие разрыва соединения. Особенно при использовании Classic Firebird SQL Server важно своевременно освобождать ресурсы, занимаемые такими фантомными соединениями.

Если имеются пользователи, подключающиеся к серверу через модемы, то достаточно велика вероятность обрыва модемного соединения в самый неподходящий момент.

Например, клиент сохраняет измененный набор записей. После выполнения UPDATE, но до выполнения COMMIT модемное соединение разрывается. Обычно клиентское приложение в такой ситуации восстанавливает соединение с сервером, но клиент, продолжая работу с теми же данными, при сохранении которых он получил сообщение об ошибке по причине разрыва соединения, не может сохранить свои изменения, получая со стороны сервера сообщение о конфликте блокировки. Ему мешает его предыдущее соединение, открывшее транзакцию, в контексте которой был выполнен UPDATE, но не был выполнен COMMIT, т. к. соединение со стороны клиента было разорвано.

Точно так же обрывы соединений могут возникать и в локальной сети, если сбоит оборудование – сетевые карты, хабы, коммутаторы – или возникают помехи. В interbase.log/firebird.log обрывы коннектов tcp показываются как ошибки 10054 (Windows. на Unix – 104), обрывы netbeui – как ошибки 108/109.

Для отслеживания и отключения таких «мертвых» соединений InterBase и Firebird использует один из двух механизмов – DUMMY-пакеты (реализован на прикладном уровне начиная с InterBase 5.0 между сервером InterBase/ Firebird и клиентской библиотекой gds32/fbclient, включается в ibconfig/firebird.conf и в данном документе рассматриваться не будет) и KEEPALIVE-сокеты (используется по умолчанию начиная с InterBase 6.0). Использование KEEPALIVE включается установкой опции сокета SO_ KEEPALIVE при его открытии. Вам не нужно специально заботиться об этом, если вы используете Firebird 1.5 или выше – это реализовано в программном коде сервера Firebird, как для Classic, так и для Superserver. Для InterBase и Firebird (младше 1.5) в варианте Classic (существуют только для Unix/ Linux) необходима дополнительная настройка (см. п. 3). В этом случае отслеживание состояния соединения возлагается не на сервер Firebird, а на стек TCP операционной системы. Однако для практического использования требуется настройка параметров KEEPALIVE.
 
Примечание. Как показывает практика, устойчивость работы механизма dummy-пакетов, реализованная еще в InterBase 5.0 и неоднократно исправленная в Firebird 1.5. x сильно зависит от операционных систем клиента и сервера, версий стека tcp и множества других условий. То есть, эффективность такой системы в реальной сети стремится к нулю. Ко всему прочему, в Borland Developer Network упоминалось, что для Windows существует проблема с утечкой памяти в adf.sys при использовании dummy-пакетов. Именно поэтому необходимо настраивать механизм KEEPALIVE, за который отвечает стек tcp клиента и сервера.
 

Описание KEEPALIVE

Поведение KEEPALIVE-сокетов регулируется параметрами, представленными в таблице:
Параметр Описание
KEEPALIVE_ TIME Интервал времени, по истечении которого начинаются пробы KEEPALIVE
KEEPALIVE_INTERVAL Интервал времени между пробами KEEPALIVE
KEEPALIVE_PROBES Количество проб KEEPALIVE
Стек TCP отслеживает момент прекращения прохождения пакетов между клиентом и сервером, запуская таймер KEEPALIVE. Как только таймер достигнет величины KEEPALIVE_ TIME, стек TCP сервера выполняет первую пробу KEEPALIVE. Проба – это пустой пакет c флагом ACK, отправляемый клиенту. Если на стороне клиента все в порядке, то стек TCP на клиентской стороне посылает ответный пакет с флагом ACK и стек TCP сервера, получив ответ, сбрасывает таймер KEEPALIVE. Если клиент не отвечает на пробу, то пробы со стороны сервера продолжают выполняться. Их количество равно KEEPALIVE_ PROBES и выполняются они через интервал времени KEEPALIVE_ INTERVAL. Если клиент не ответил на последнюю пробу, то по истечении еще одного интервала времени KEEPALIVE_ INTERVAL стек TCP операционной системы сервера закрывает соединение и Firebird высвобождает все ресурсы, занимаемые обслуживанием данного соединения.

Таким образом, разорванное клиентское соединение будет закрыто по истечении времени KEEPALIVE_ TIME+ ( KEEPALIVE_ PROBES+1)* KEEPALIVE_ INTERVAL.

Значения параметров по умолчанию достаточно велики, что делает их практическое применение неэффективным. Параметр KEEPALIVE_ TIME, например, имеет значение по умолчанию 2 часа и в Linux и в Windows. Реально достаточно одной-двух минут для принятия решения о принудительном отключении недоступного клиента. С другой стороны, настройки KEEPALIVE по умолчанию иногда приводят к принудительному обрыву соединений в сетях Windows, которые неактивны в течение этих самых двух часов (сомнения по поводу необходимости наличия в приложениях таких соединений – это уже другой вопрос).

Ниже мы рассмотрим настройку этих параметров для операционных систем семейства Windows и операционной системы Linux.
 

Настройка KEEPAILVE в Linux

Параметры KEEPALIVE в Linux можно изменить либо прямым редактированием файловой системы / proc либо вызовами sysctl.

Для первого случая надо редактировать:
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_intvl
/proc/sys/net/ipv4/tcp_keepalive_probes

Для второго случая выполнить команды:
sysctl –w net.ipv4.tcp_keepalive_time=value
sysctl –w net.ipv4.tcp_keepalive_intvl=value
sysctl –w net.ipv4.tcp_keepalive_probes=value

Время задается в секундах.

Для автоматической установки этих параметров в случае перезагрузки сервера добавьте в /etc/sysctl.conf:
net.ipv4.tcp_keepalive_intvl = value
net.ipv4.tcp_keepalive_time = value
net.ipv4.tcp_keepalive_probes = value

Слово <value> замените на нужные вам величины.

Если вы используете Firebird Classic ранее версии 1.5, то в /etc/xinet.d/firebird пропишите следующее:
FLAGS=REUSE KEEPALIVE
 

Настройка KEEPALIVE в Windows 95/98/ME

Ветка реестра:
HKEY_ LOCAL_ MACHINE\System\CurrentControlSet\Services\VxD\MSTCP

Все про настройку TCP здесь: http://support.microsoft.com/default.aspx?scid=kb;en-us;158474

Параметры:
  • KeepAliveTime = миллисекунды
Тип: DWORD
Для Windows 98, тип STRING.
Определяет время неактивности соединения в миллисекундах по истечении которого начинаются KEEPALIVE-пробы. Значение по умолчанию – 2 часа (7200000).
  • KeepAliveInterval = 32-значное число
Тип: DWORD
Для Windows 98, тип STRING.
Определяет время в миллисекундах между повторами KEEPALIVE-проб. Как только истек интервал KeepAliveTime через каждый интервал времени KeepAliveInterval (в миллисекундах) посылаются KEEPALIVE-пробы максимальным количеством MaxDataRetries. Если ответ не придет, соединение закрывается. Значение по умолчанию 1 секунда (1000).
  • MaxDataRetries = 32-значное число
Тип: STRING
Определяет максимальное количество KEEPALIVE-проб. Значение по умолчанию 5.
 

Настройка KEEPALIVE в Windows 2000/NT/XP

Ветка реестра:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\.

Все про настройку TCP: Вместо MaxDataRetries используется параметр TCPMaxDataRetransmissions. Остальные параметры называются так же, как для Windows 9x.


Настройка KEEPALIVE в Windows (для клиентов)

Данная настройка необязательна, но, возможно, позволит уменьшить количество сообщений о потере соединения при использовании ненадежных линий связи. Добавьте в ветку реестра
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
параметр DisableDHCPMediaSense=1. См. описание данного параметра здесь: http://support.microsoft.com/?scid =kb%3Bru%3B239924&x=13&y=14.

Рассмотрим пример настройки Firebird SQL Server 1.5.2 CS под ОС Linux:
  • Убедимся, что в firebird.conf отключен механизм DUMMY-пакетов (параметр закомментирован)
..............
#DummyPacketInterval=0
..............
  • Убедимся в наличии конфигурационного файла /etc/xinet.d/firebird
В нем все оставляем по умолчанию, как прописано при установке. Ничего добавлять не надо.
  • Изменяем параметры стека TCP
sysctl –w net.ipv4.tcp_keepalive_time = 15
sysctl –w net.ipv4.tcp_keepalive_intvl = 10
sysctl –w net.ipv4.tcp_keepalive_probes = 5
  • Устанавливаем соединение к любой базе данных на сервере с любого сетевого клиента.
  • Смотрим трафик на сервере используя любой фильтр пакетов.
При указанной конфигурации параметров /proc/sys/net/tcp_ keepalive_* через 15 секунд с момента наступления тишины в канале сервером выполняется проба. Если клиент жив, то серверу высылается ответный пакет. Еще через 15 секунд проверка повторяется и т. д.
  • Если клиента отключить физически (выключить коммутатор или модем – мало ли, что может случиться в действительности), то на пробу сервера ответ от клиента не приходит, и сервер начинает с 10-ти секундным интервалом посылать пробы. Если на пятую пробу клиент не ответил, то еще через 10 секунд серверный процесс выгружается, освобождая ресурсы и блокировки. Если клиент подал признаки жизни и откликнулся хотя бы и на пятую пробу (худший случай), то снова выдерживается 15-сек тайм-аут и опять начинаются пробы. И т. д.
 

Заключение

В заключение хотелось бы привести практические рекомендации по выбору величин параметров KEEPALIVE.

Во-первых, определите для себя необходимую величину параметра KEEPALIVE_TIME. Чем больше будет его значение, тем позже начнутся KEEPALIVE-пробы. Если вы постоянно наблюдаете на своем сервере множество зависших коннектов, и вам приходится их удалять вручную, то следует уменьшить величину KEEPALIVE_TIME.

Во-вторых, значения параметров KEEPALIVE_INTERVAL и KEEPALIVE_PROBES должны удовлетворять вашим требованиям по своевременному отключению уже обнаруженных системой зависших соединений. Если ваши пользователи устанавливают соединения с сервером через ненадежные каналы связи, то вам, возможно, захочется увеличить количество проб и интервал между ними для того, чтобы пользователь успел обнаружить обрыв и восстановить соединение с сервером. В случае, если клиентоы используют выделенное подключение к сетям общего пользования (Интернет) или используют доступ к SQL-серверу по локальной сети, возможно уменьшение количества и интервала между KEEPALIVE-пробами.

Общие рекомендации могут звучать так: если вы на практике получаете большое количество сообщений от клиентов об ошибках сохранения результатов работы по причине конфликта блокировки без видимых на то причин, т. е. при отсутствии конкурирующих соединений, работающих с теми же данными, то вам надо увеличивать реакцию системы на отключение зависших коннектов. Практически величина KEEPALIVE_TIME может составлять от 1 минуты и более – вы сами должны оценить время выполнения самой длительной транзакции в системе, чтобы не перегружать сетевой трафик KEEPALIVE-проверками нормально работающих соединений, запустивших длительные транзакции. Величина KEEPALIVE_INTERVAL – от 10 секунд и более, а величина KEEPALIVE_PROBES – от 5 проверок и более. Помните, что большое количество проверок и малый интервал между ними могут существенно увеличить сетевой трафик при большом количестве одновременно работающих пользователей.

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

И, наконец, еще несколько примеров общих конфигураций. Под временем простоя будем подразумевать время, в течение которого пользователи не смогут обновить данные, обновление которых начато транзакцией, открытой зависшим соединением. Итоговое время – это время, по истечении которого зависшее соединение будет закрыто.
  • Клиенты используют модемные соединения, в системе преобладают короткие транзакции, время простоя ограничено 3 минутами.
KEEPALIVE_TIME 1 минута
KEEPALIVE_PROBES 3
KEEPALIVE_INTERVAL 30 секунд
ИТОГО 3 минуты
  • Клиенты используют доступ по локальной сети, в системе преобладают короткие транзакции, время простоя ограничено 2 минутами.
KEEPALIVE_TIME 30 сек
KEEPALIVE_PROBES 5
KEEPALIVE_INTERVAL 10 сек
ИТОГО 90 секунд
  • Клиенты используют любые соединения, время простоя не регламентируется.
KEEPALIVE_TIME 15 мин
KEEPALIVE_PROBES 4
KEEPALIVE_INTERVAL 1 мин
ИТОГО 20 минут
  • Клиенты используют любые соединения, в системе возможны длительные транзакции, время простоя ограничено 15 минутами.
KEEPALIVE_TIME 12 мин
KEEPALIVE_PROBES 7
KEEPALIVE_INTERVAL 15 сек
ИТОГО 14 минут
 
Надеемся, приведенных примеров будет достаточно для правильной настройки механизма KEEPALIVE стека TCP.
Впервые опубликовано с разрешения автора на www.ibase.ru, 2005. 

Подпишитесь на новости Firebird в России

Подписаться