InterBase: тормозология и глюконавтика
Страница 19. Глюки с целостностью


Глюки с целостностью

Кроме того, что InterBase - не самый эффективный сервер, он ещё и не самый надёжный. Здесь я не буду рассматривать наиболее клинический случай (5.0), но тем не менее... Ненадёжность проявляется во многих формах: и в том, что сервер может внезапно повиснуть, и в том, что может непредсказуемо запороться файл БД, и в том, что корректные операции или их последовательности приводят к некорректным результатам, и в том, что средства диагностики всё это дело не всегда вылавливают. (А не глюк ли, что во всём мире это называется InterBase, а у нас - interbase Database?). Тем не менее, если придерживаться определённых принципов, то неприятностей можно избежать. Но всё по порядку.

Как InterBase падает

Что касается причин падения, то во-первых, InterBase, как и любая другая программа, может упасть от того же, что и соответствующая платформа вообще. Здесь работает очевидная истина: выбор "падучей" системы вроде Windows рано или поздно выйдет боком. Но народ в наше время обычно предпочитает тупо терпеть.

Так же необходимо следить и за железом. Полезно провести тесты с копированием больших файлов (десятки, лучше - сотни МБ) и куч мелких файлов (тысячи, лучше - десятки тысяч) с последующим сравнением скопированного. Если копии разошлись, то сервер на такую машину ставить однозначно нельзя. Если не поможет смена софта (драйверов или всей операцонки), то такую машину лучше выкинуть. Разумеется, отрицательным образом на надёжности сказываются разного рода "разгоны" железа.
Второй фактор, определяющий падучесть - архитектура сервера. Дело в том, что лично мне за всё время приходилось видеть три способа организации вычислений внутри InterBase.

  1. Классический для Unix способ с порождением отдельного процесса на каждое пользовательское соединение (gds_inet_server) + ещё 1 общерулящий процесс (gds_lock_mgr). Такая архитектура является наиболее надёжной, так как общий процесс выполняет мало функций (пользовательские запросы в него не заходят вообще) и практически никогда не падает, а падение обслуживающего процесса затрагивает только одного клиента и система в целом остаётся работоспособной. По такой технологии, насколько я знаю, работают серверы InterBase до 4.0 включительно, кроме NetWare.
  2. Новомодная ныне многопоточная технология, основанная на переделывании "многопроцессной" версии. Состоит в том, что все параллельные единицы исполнения (обзываемые в данном случае потоками) сваливаются в общую кашу в пределах одного процесса. InterBase 4.0 for NetWare, а так же большинство воплощений 4.2 представляют собой один многопоточный процесс, однако в основе потоков лежит тот код, который раньше работал в отдельных процессах. Так что надёжность отдельного потока примерно та же. Это даёт небольшой выигрыш в производительности, хотя по-моему, если бы Борланд направил силы на улучшение оптимизатора запросов, пользы было бы гораздо больше. В общем, теперь сбой в одном потоке валит весь сервер.
  3. Сервер 5.х, переписанный специально под многопоточную архитектуру. Окончательная деградация надёжности, отдельный случай.

Следующий фактор - способ использования сервера. Если в базе хранятся простые таблицы с минимальным количеством ограничений и к ним идут простые запросы, то всё может работать вполне надёжно. Если же пытаться использовать навороченные средства, то иногда можно добиться жутких результатов.
Ещё один важный источник глюков - модули внешних функций (external function, UDF), разновидностью которых являются блобовые фильтры (blob filters). С одной стороны, это хорошо, что Борланд даёт возможность доделывать те вещи, которые не желает делать сам. Но с другой стороны - всё это реализовано по принципу: "шаг влево, шаг вправо - расстрел". То есть нормально в этих библиотеках работают только функции, которые читают параметры, что-то внутри себя вычисляют (скажем, ищут подстроку), и возвращают единственный скалярный результат. Если попытаться обратиться к какому-либо внешнему модулю, установить с кем-либо связь, вызвать исключение, и т. п., то результаты непредсказуемы. В том смысле, что неизвестно: вылетит сразу или потом, в неподходящий момент. Причём на каких конкретно принципах основаны ограничения, что можно, а что нельзя - непонятно.

Есть правда слухи, что начиная с 5.5 interbase научился корректно перехватывать исключения, вылетающие из UDF, но в остальных версиях, как я видел, ни чем хорошим это не кончалось.

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

То есть ни сервер не защищён от модулей, ни модули от сервера. Единственная защищённая от функций версия, которую я видел - InterBase for NetWare. Там внешние функции просто не поддерживаются, что в прочем не мешает ему рушить всю систему по другим причинам.

Кроме этого в некоторых случаях наблюдались совсем странные падения в момент, когда один пользователь модифицировал метаданные, а другие в это время обращались к соответствующим данным. К сожалению, глюк настолько мимолётный и неожиданный, что подробно изложить условия и причины я затрудняюсь.
Последствия падения можно разделить на три вида: повреждения БД, повреждения системы и разорванные соединения. Повреждения системы определяются её архитектурой и колеблются от "гарантированно валится всё" (NetWare) до "исчезает одно соединение с клиентом" (Unix без потоков).

Про наиболее распространённую платформу, Windows могу сказать, что падение InterBase повреждает её хоть и не всегда, но относительно часто. Причём это по моим наблюдениям в равной степени касается и Win90, и NT. Наиболее любимый трюк первой (на моём компьютере) - оставить в памяти какой-то процесс, который пожирает производительность. Когда отлаживаешь что-либо и сервер падает по несколько раз, торможение становится всё заметнее, пока работа не станет совсем невозможной. Замечено, что тормозящий процесс остаётся тогда, когда на момент падения к серверу было более одного подключения. В общем, убивайте внимательно.

Что же касается NT, то в ней повреждения проявляется в виде какой-то внутренней ошибке при попытке вновь запустить сервис InterBase.

Соединения клиента с InterBase, как известно, бывают четырёх видов:

  • Local - участок общей памяти, когда клиент и сервер работают в одной машине
  • TCP/IP - протокол Internet и сетей Unix
  • SPX/IPX - протокол сетей NetWare
  • NetBEUI - протокол сетей Microsoft и interbaseM
Наиболее надёжный из них - первый. Как только на одном конце соединения происходит авария, соединение закрывается. Но по сети он, понятное дело, работать не будет. Из сетевых мне представляется наиболее удобным TCP/IP. Во-первых, работает везде. NetBEUI не работает с NetWare, IPX, наоборот, только с NetWare, а сервер под Win95 вообще поддерживает сетевой обмен только через TCP/IP. Во-вторых, этот протокол быстрее любых других выясняет о разрыве соединения на другом конце.
По крайней мере это дело контролируемо, и даже под Виндами. По некоторым данным в реестре, в HKEY_LOCAL_MACHINE \ CurrentControlSet \ Services \ VxD \ MSTCP имеются параметры:
  • KeepAliveTime - время в миллисекундах, в течение которого TCP/IP ждёт в режиме бездействия содинения, прежде чем начать его тестировать. По умолчанию стоит два часа (охренел малость Мелкософт). При работе с локальными сетями лучше поставить одну-две минуты, а при наличии доступа в Инет - минут 10 - 15 (переведя в миллисекунды, разумеется).
  • KeepAliveInterval - время между тестовыми пакетами, тоже  в миллисекундах. По умолчанию - 1 секунда.
  • MaxDataRetries - количество тестовых пакетов. Если после данного количества тестов не получено ни одного ответа, соединение считается разорванным.
Я пробовал с ними экспериментировать, но ничего хорошего не добился. Под NT вписывание этих параметров в нужную ветку просто ни к чему не привело. Под 95 привело. К тому, что соединение просто обламывалось при истечении таймаута бездействия. То есть тестовых пакетов будто и не было. Дальше следовало бы поработать сетевым анализатором - что там реально происходит. Но на это нужно время и желание ...

Остаётся надеяться только на меры со стороны разработчиков будущих версий. В interbase 5.6 согласно документации в файле interbaseCONFIG появилась пара новых параметров - CONNECTION_TIMEOUT nnn и DUMMY_PACKET_INTERVAL nnn. Оба делают примерно то же самое, но независимо от транспортного протокола. Первый параметр задаёт время в секундах, после которого закрывается неоткликающееся соединение, а второй - интервал между тестовыми запросами в время бездействия соединения. По умолчанию оба параметра закомментированы и в интерфейс нигде не выведены. Рекомендуется поставить руками, скажем, 160 и 50.

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

Что совсем противно, так это то, что сообщения об ошибках связи обычно содержат числовые коды и ничего не говорят о причине происходящего. Даже о сети часто вообще не упоминается.

Когда же падает клиент, на сервере остаётся открытое соединение, через которое сервер ждёт запросов. Если соединения каким-либо способом учитываются (скажем, не допускается повторное подключение того же пользователя), то "висячие" соединения создадут проблемы. В прочем, для TCP/IP это лечится всё тем же способом.

И уж раз мы говорим про соединения, то упомяну ещё одну особенность комбинации NetBEUI + NT. В этом варианте поток, обслуживающий клиента, работает "от имени" этого клиента. Это значит, что чтобы иметь доступ к базе ему мало быть зарегистрированным в interbase. Надо быть также зарегистрированным в NT и войти в сеть MS под таким именем, чтобы NT к себе пустила. И в довершение ко всему нужно, чтобы у пользователя NT были права на чтение и запись файла БД. Если хотя бы одно звено в этой цепочке маразмов не выполнено, то NT может не пустить к себе соединение NetBEUI. Смысл этой защиты тем более неясен, что соединение TCP/IP в тех же самых условиях проблем не создаёт.

 
« Предыдущая статья