Автор: Овчинников Василий
mailto: ova@tkvc.ru
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
Параметры :
- 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:
XP: http://support.microsoft.com/kb/314053
Вместо MaxDataRetries используется параметр
TCPMaxDataRetransmissions.
Остальные параметры называются так же, как для Windows 9x
Настройка KEEPALIVE в Windows (для клиентов)
Данная настройка необязательна, но, возможно, позволит уменьшить количество сообщений о потере соединения при использовании ненадежных линий связи. Добавьте в ветку реестра
HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Services\ Tcpip\ Parameters
параметр DisableDHCPMediaSense=1 . См. описание данного параметра здесь:
https://support.microsoft.com/ru-ru/help/239924/how-to-disable-the-media-sensing-feature-for-tcp-ip-in-windows
Пример
Рассмотрим пример настройки 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.
Программа работает в среде Windows XP/Vista/7/8.1/10/11, Server 2003/2008/2012/2016/2019/2022. Вы можете скачать и попробовать 30-дневную пробную версию бесплатно.