Несмотря на активную шумиху в высших сферах по поводу разработки и внедрения отечественного программного обеспечения (ПО), Группа компаний РЕЛЭКС продолжает разрабатывать и внедрять отечественную СУБД ЛИНТЕР. Мы, конечно, надеемся, что интерес к нашим разработкам рано или поздно проснётся и на государственном уровне, а пока продолжаем поддерживать и развивать отечественную СУБД самостоятельно. В этой деятельности нам очень помогают наши клиенты и партнёры, которые «не убоялись» использовать ПО, полностью разработанное в России. Мы уверены, что они окажутся в выигрыше.
Так получается, что многие наши заказчики используют в своей работе операционные системы (ОС) реального времени. СУБД ЛИНТЕР изначально проектировалась так, чтобы удовлетворять ограничениям, которые накладывает функционирование в таких ОС. Практика показала, что наша архитектура достаточно гибка для переноса в разные программно-аппаратные среды. В результате, мы имеем СУБД, которая функционирует в различных ОС реального времени (QNX 4, QNX6, VxWorks, ОС РВ, OS/9, OS9000) и на различных аппаратных платформах (x86, PPC, Sparc, ARM, MIPS. 68K и т.п). И это не считая Windows CE и linux различных модификаций. При этом обеспечивается полная совместимость по протоколам взаимодействия между узлами под управлением разных ОС, что позволяет использовать единую инфраструктуру и для технологического оборудования и для аналитических систем.
Наша компания на протяжении последних лет регулярно участвует в конференции «Корпоративные базы данных», но ранее мы не делали акцента на использование СУБД в системах реального времени. Учитывая постоянно растущий интерес к разработке эффективного ПО в системах реального времени, настало время наверстать это упущение.
В докладе мы опишем возможности ЛИНТЕР для решения задач, особенности функционирования в системах реального времени и планы развития СУБД в этом направлении.
Как уже было сказано выше, для нас практически не существует ограничения на выбор программно-аппаратной платформы для функционирования СУБД – причём не только для клиентской части, но и для серверной – ядра. Это позволяет организовывать произвольные конфигурации приложений на встраиваемом оборудовании. Вы можете использовать модули только как датчики, передавая информацию на сервер БД по сети, а можете использовать автономное хранилище на модуле с периодической синхронизацией всех или агрегированных данных на основной сервер.
Сильной стороной нашего решения являются небольшие требования к оперативной памяти – даже для полного серверного варианта, ЛИНТЕР может поместиться в 4Мб оперативной памяти. Хотя существуют специальные версии ядра СУБД, которые занимают в памяти менее 1Мб (разумеется, за счёт ограничения возможностей). Для клиентского же варианта, требования ещё более скромные — порядка 100Кб.
Кроме небольших требований к ресурсам, важным фактором использования СУБД в системах реального времени является постоянство используемых ресурсов, или возможность ограничения ресурсов. Мы гарантируем постоянство использования оперативной памяти (вне зависимости от объёма БД, сложности выполняемых запросов и количества одновременно работающих пользователей и приложений) и постоянство максимального числа одновременно открытых файловых дескрипторов (вне зависимости от количества файлов БД).
Мы учитываем возможность роста файлов БД, временных файлов, файлов регистрации событий в СУБД и т.п. Например, файлы мониторинга событий в СУБД могут быть запрещены, а могут быть закольцованы – при этом предыдущий файл при достижении определённого размера переименовывается для удобства архивирования, а последние сообщения будут всегда добавляться в новый файл, но с одним и тем же именем. При этом могут быть введены ограничения на размер кольца старых файлов. Подобная схема позволяет или периодически сбрасывать файлы регистрации событий в архив или просто иметь информацию по длительному периоду функционирования СУБД без опасности переполнить этой информацией диск.
При создании базы данных существует возможность гибкой конфигурации расположения файлов БД. Возможно размещение файлов разных таблиц и типов на разных устройствах. Это особенно актуально при эксплуатации СУБД во встроенной технике – в случае, когда различные устройства имеют разные характеристики по скорости и надёжности хранения информации. Например, файлы журналов могут располагаться на более быстром носителе небольшого объёма, а файлы БД на более медленном, но большого объёма. Крайним вариантом такого решения является вариант использования «read only» базы данных, когда БД расположена на носителе без возможности перезаписи. В процессе эксплуатации возможна миграция отдельных таблиц или файлов с устройства на устройство, что тоже иногда полезно в случае, если средства самодиагностики предсказывают скорый отказ устройства.
СУБД ЛИНТЕР обеспечивает целостность БД в случае аварийного отключения питания за счёт ведения журнала транзакций и целостности БД. Наличие журнала и механизмы восстановления базы данных гарантируют восстановление БД после сбоев по питанию, что особенно важно для технологических и встроенных необслуживаемых систем, которые обычно и разрабатываются с использованием операционных систем реального времени.
Отличительной особенностью интерфейса СУБД ЛИНТЕР является полная асинхронность. Любой запрос, поданный ядру СУБД, будет выполняться асинхронно. Разумеется, в случае, если асинхронность не требуется, то интерфейс ЛИНТЕР будет сам ожидать завершения работы запроса, но внутри запросы будут выполняться асинхронно. В обычных системах это не очень важно, так как обычно не требуется фиксированное время реакции на внешние события. В системах реального времени возможность продолжать обработку данных вне зависимости от реакции хранилища данных очень важна.
Во время обработки запроса к БД можно продолжать обработку входных данных или управлять исполнительными устройствами. В случае каких-то задержек при работе с БД (вызванных, например, задержками на сети или временным отказом сети), можно обеспечить буферизацию данных и, после восстановления связи, загрузить данные на сервер. При этом реализация интерфейса ЛИНТЕР позволяет как опросить состояние завершённости запроса, так и предоставить асинхронный обработчик, который будет вызван интерфейсом в момент завершения запроса. В этом обработчике тоже можно послать запрос (!) к БД (правда, уже только асинхронный). Таким способом можно реализовать цепочную обработку множества запросов асинхронно к выполнению основной программы.
Следует учитывать также, что интерфейс ЛИНТЕР позволяет функционировать многонитевым приложениям — все синхронизации обмена с БД выполняются прозрачно для программы. Нити могут также работать асинхронно. Таким образом, программный интерфейс ЛИНТЕР позволяет организовать любую архитектуру приложения – как многонитевую с различными приоритетами нитей, так и сигнальную с различными приоритетами сигналов и с минимальной задержкой на подготовку и отправку асинхронного запроса.
Дополнительной возможностью для повышения производительности является возможность предварительной трансляции запросов. В случае такой трансляции, при выполнении запроса уже не требуется его синтаксически разбирать, вырабатывать план выполнения и т.п. В полностью готовом к исполнению запросе необходимо будет только подставить параметры (если они есть) и его можно выполнить. При этом в отличие от некоторых реализаций в других СУБД, после привязки новых значений параметров не требуется повторной трансляции запроса. Разумеется, при выполнении запроса выполняется контроль объектов, участвующих в запросе. Использование подобной возможности в комбинации с асинхронным выполнением запросов позволяет получить очень эффективный код для выполнения однотипных запросов. Типичный пример — регистрация информации с датчиков.
В случае необходимости – в вариантах использования ядра ЛИНТЕР без транслятора SQL или в случае, если не хочется передавать исходные тексты запросов – можно использовать «статический SQL» – предварительно скомпилированные запросы в двоичной форме, сохранённые в тексте приложения. При этом будут сохранены все возможности СУБД, как по набору выполняемых запросов, так и по возможностям интерфейса. Отсутствие трансляции SQL-запроса не освобождает ядро от необходимости проверки доступа к данным и объектам. Разумеется, ЛИНТЕР обеспечивает эти проверки вне зависимости от способа трансляции и/или исполнения запроса.
В СУБД мы не могли обойти вниманием такое понятие, как приоритеты исполнения запросов. В системах реального времени этому вопросу уделяется особое внимание. Возможность исполнения запросов с различными приоритетами была заложена в ЛИНТЕР с самых первых версий и с тех пор значительно усовершенствована.
Мы предлагаем три класса приоритетов исполнения запросов: обычные приоритеты, приоритеты Round Robin и приоритеты реального времени.
Приоритетов реального времени 50. Запрос с подобным приоритетом будет выполняться до тех пор, пока не выполнится или пока не появится запроса с приоритетом выше его собственного.
Приоритетов Round Robin 100. Запросы с таким приоритетом квантуются поровну на каждом уровне приоритета, не позволяя исполняться запросам с приоритетами ниже их собственного, но немедленно прерываясь при появлении запроса с приоритетом выше (в том же классе или в классе реального времени).
Запросы с обычными приоритетами (их тоже 100) выполняются по принципу: чем выше приоритет, тем больше времени запросу будет выдано. При этом выполняются запросы со всеми обычными приоритетами; просто те, у кого приоритет выше выполняются быстрее, а те, у кого меньше – медленнее. Для запросов с обычными приоритетами предусмотрена ещё и коррекция приоритета – в случае, если запрос выполняется долго, его приоритет может быть понижен системой в определённых ранее пределах для того, чтобы обеспечить более быстрое исполнение коротких запросов.
Приоритетами исполнения запросов можно управлять в процессе работы системы через специальные управляющие команды. То есть оператор, отслеживая нагрузку системы и скорость реакции, может изменить приоритет того или иного запроса. Кроме изменения приоритета возможна вообще отмена выполнения или приостановка выполнения запроса на некоторое время.
Очень мощным аппаратом СУБД ЛИНТЕР, активно используемым в системах реального времени, является аппарат событий. Событие представляет собой объект синхронизации распределённых приложений или извещения приложений об изменении в данных.
Событие – именованный объект, который связан с выполнением некоторой операции (добавлением, удалением или изменением записей) над определённой таблицей или с успешным выполнением некоторого SQL-запроса. В первом случае всё ясно – событие устанавливается в случае, если в таблицу, с которой оно связано, выполняется соответствующая операция (одна или несколько). А во втором случае изменение любой из таблиц, использованных в SQL-запросе, с которым событие связано, приводит к исполнению указанного запроса и, в случае, если запрос вернул непустой ответ, событие тоже устанавливается. Второй режим очень удобно использовать при параллельной работе нескольких приложений.
Для события справедливы операции опроса или ожидания наступления. При этом возможны различные комбинации по «И» или «ИЛИ». То есть приложение может ожидать не одно, а несколько событий в различных комбинациях. Если ожидаемая комбинация событий наступила, то операции ожидания событий завершаются. Вместе с возможностью асинхронного исполнения запросов и асинхронной нотификации о завершении запроса, этот механизм оказывается очень полезным при разработке приложений, функционирующих в условиях реального времени. В настоящее время мы очень сильно модернизируем аппарат событий, но о новых возможностях будет сказано ниже.
В качестве промежуточного хранилища данных СУБД ЛИНТЕР предоставляет два развитых интерфейса – временные таблицы и таблицы «в памяти».
Временные таблицы соответствуют спецификации глобальных временных таблиц SQL. Они позволяют под одним именем таблицы видеть собственные копии с собственными данными.
Таблицы «в памяти» гарантированно располагаются только в оперативной памяти, им не требуются дополнительные ресурсы – они всегда доступны для приложения и работа с ними не журнализируется, что значительно повышает производительность. В случае любой ошибки в данных или конфликта транзакций, такая таблица откатывается на последнее сохранённое состояние. Разумеется, можно всегда сохранить очередную копию таблицы. Обе эти возможности очень сильно повышают производительность приложений, работающих с большим количеством временных данных.
Возможности пакетной загрузки и извлечения данных является хорошим дополнением к возможностям асинхронной работы – они позволяют продолжать обработку информации параллельно с её загрузкой большими порциями. Для загрузки предварительно необходимо подготовить ядро к приёму записей одним пакетом, выполнив специальный запрос. После этого возможна передача нескольких записей одним пакетом. Для массового извлечения данных необходимо использовать специальные команды, которые практически полностью совпадают с обычными командами извлечения данных. Эти возможности сильно повышают производительность при работе с большими объёмами информации. Причём, если массовое извлечение данных в системах реального времени присутствует редко, то массовая загрузка используется достаточно активно – особенно в случае, если связь с БД была прервана, и накопилось много данных в буферах.
Завершает список наиболее востребованных в системах реального времени возможностей простота интеграции СУБД ЛИНТЕР в программные пакеты. Для установки СУБД, как клиентской, так и серверной частей не требуется специальная процедура установки. При разработке процедуры установки приложения возможна установка любых компонент системы простым копированием файлов и созданием простых скриптов для запуска. Возможно создание БД или изменение её параметров в произвольные моменты времени – быстро и без запуска специальных средств. Эта возможность облегчает установку и работу с СУБД – можно устанавливать только необходимые компоненты и делать это через общую процедуру установки приложения.
Возможности ЛИНТЕР не исчерпываются перечисленными выше пунктами. Рассмотрим кратко крупные подсистемы, реализованные в нашей СУБД.
Подсистема безопасности. Это одно из главных направлений развития ЛИНТЕР. Наша компания имеет все необходимые лицензии в области разработки защищённого ПО, что позволяет сертифицировать наши продукты в различных организациях. Часть наших продуктов имеет сертификаты ФСТЭК по 2 классу защиты информации от НСД и на отсутствие недекларированных возможностей.
Подсистема безопасности включает в себя дискреционную и мандатную защиты, аудит, защиту сетевых подключений, защиту ввода-вывода на отдельные устройства и т.п. Разумеется, учитывается и необходимость защиты от различных видов атак, различные расписания работы отдельных сетевых узлов и т.п. Мы предлагаем возможность полного шифрования БД, что исключает извлечение информации даже в случае физической утраты носителя с БД. При необходимости мы разрабатываем встроенные специализированные варианты ядра СУБД, которые удовлетворяют специфическим требованиям, и помогаем сертифицировать эти решения в составе комплекса ПО заказчиков.
Подсистема полнотекстовой индексации. ЛИНТЕР позволяет строить полнотекстовые индексы по текстовым полям и различным типам документов. Документы могут как храниться в БД, так и располагаться на файловой системе. ЛИНТЕР обладает развитым интерфейсом поисковых запросов по этому индексу, позволяет искать фразы, слова, частично известные слова, группы слов с учётом расстояния и т.п. Полнотекстовый индекс очень компактен и обеспечивает очень быстрый поиск. При этом для поиска не требуется специальных конструкций — достаточно указать дополнительный предикат в обычном SQL-запросе.
Подсистема работы с геометрической информацией. В составе СУБД присутствует возможность работы с геометрической информацией в соответствии со стандартом OpenGIS.
Подсистема архивирования. Подсистема позволяет архивировать отдельные таблицы БД или БД целиком. Для архивирования не требуется останавливать работу с БД — параллельно с процессом архивирования могут выполняться приложения, модифицирующие БД. При этом будет гарантирована транзакционная целостность архивной БД. В случае архивирования БД целиком, возможно инкрементное архивирование, что позволяет архивировать только накопившиеся с момента последнего архивирования изменения. Ещё один вариант работы – архивирование с ожиданием изменений. В этом случае изменения одновременно с поступлением в БД поступают и в архив. Архивирование может выполняться отдельной утилитой как локально, так и через сеть или по расписанию ядром СУБД в соответствии с правилами или подачей SQL запросов на создание архивов.
Подсистема горячего резервирования. Одна из самых важных подсистем для использования в отказоустойчивых системах. Наш горячий резерв обеспечивает функционирование нескольких узлов БД как единой системы с автоматическим переключением приложений в случае выхода из строя отдельных узлов. При этом обеспечивается возможность связи узлов горячего резерва параллельно по нескольким линиям связи с автоматическим переключением в случае отказа линий. Время переключения на резервный сервер в случае отказа основного занимает несколько секунд, что является небольшой платой за возможность обеспечения непрерывного доступа к БД.
К другим свойствам ЛИНТЕР, которые доступны для использования, относятся поддержка сверхбольших объёмов памяти для кэширования (в 64-битных ОС), поддержка длинных файлов (в файловых системах, которые поддерживают такие файлы), поддержка Oracle-расширений (join, connect by, функций и т.п), поддержка расширений стандарта SQL 2003 (sequences, аналитические функции, siblings, similar, match, select в select и т.п), триггеры и хранимые процедуры (с возможностью вызова как пользовательских функций), ссылочная целостность с возможностью отложенных проверок целостности, графические утилиты администрирования и утилиты командной строки, различные программные интерфейсы (кроме внутренних это odbc, jdbc, .NET, OLEDB, perl, php, python, Ruby) и множество других возможностей.
При перечислении наших возможностей нельзя обойти вниманием проблемы, которые возникали (и возникают) при разработке СУБД в различных ОС реального времени. Знание этих проблем, возможно, будет полезно и при разработке других программ и программных комплексов.
Общей проблемой, с которой мы периодически сталкиваемся, является минимизация объёма загруженного ядра СУБД. В последнее время актуальность этой задачи стремительно падает, но всё-таки следует сказать, что минимальные требования к памяти (включая минимальный пул памяти для работы) для нас порядка 900кб. Хотя при таком объёме СУБД утрачивает множество полезных функций. Реальный объём используемой нами памяти 2 – 4 Мб плюс пул памяти для кэширования БД. Возможность подключения и отключения отдельных компонент СУБД была обеспечена достаточно «грубым» разделением, но даже такая архитектура позволила добиться искомых результатов. Однако эта проблема не является специфичной для операционных систем реального времени, с которыми мы общались в процессе разработки.
С наиболее серьёзными проблемами мы столкнулись при переносе СУБД в операционную систему VxWorks. Особенностью этой ОС является отсутствие понятия процесса как такового. В результате, все приложения в этой ОС фактически являются нитями. При этом множество приложений могут параллельно обращаться к ядру СУБД. Внутри ядра СУБД тоже существует несколько процессов, которые взаимодействуют между собой. Не упрощают ситуацию и процессы, обеспечивающие взаимодействие с сетью. Особой проблемой были случаи завершения нитей, которые послали запросы к ядру и не дождались ответов.
При решении этой проблемы нам пришлось упорядочить глобальные переменные, добавить инициализаторы для всех статических переменных модулей, написать специальные обёртки для функций обмена приложений с ядром и для процедур запуска отдельных компонент ЛИНТЕР. Для «чистки» запросов, посланных нитями, которые завершились, не дождавшись ответа от ядра, пришлось добавить специальные cleanup функции и специальные контролирующие нити.
В результате получилось компактное решение, которое практически полностью обеспечивает функциональность системы в обычных ОС – со всеми возможностями, часто используемыми в задачах реального времени: асинхронностью выполнения запросов, асинхронной нотификации о завершении выполнения, событиями и т.п.
Разумеется, с точки зрения безопасности, общий доступ к памяти позволяет нарушить как режим безопасности, так и вообще функционирование всей системы, но при работе с сервером через сеть все проверки доступа полностью сохраняются. В результате, если в системе будет использоваться комплекс плат с ОС VxWorks, одна из которых будет выделена исключительно для выполнения функций СУБД, то такое решение может рассматриваться как защищённое.
Некоторые затруднения вызвало портирование СУБД на ОС РВ – операционную систему разработки НИИСИ РАН. Эта ОС по архитектуре подобна VxWorks, но имеет posix интерфейс. За исключением использования другого интерфейса (который, правда, более удобен на наш взгляд, чем Vx), мы столкнулись с некоторыми отличиями. Основными проблемами были доставка сигналов процессам и ошибки в реализации функции memmove – эта функция не обрабатывала ситуацию невыровненного расположения операндов на платформе, которая требует их выравнивания, и применяла процессорную оптимизацию пересылки блока данных, что приводило к «падению» по ошибке доступа к шине. К чести НИИСИ РАН следует сказать, что в последующих версиях эта проблема была устранена.
Операционная система OS/9 была первой ОС, на которую было перенесено ядро СУБД ЛИНТЕР. Ещё в 1994 году на неё была перенесена версия ЛИНТЕР 4.0. Кроме нестандартных интерфейсов межзадачного обмена и синхронизации, нам пришлось столкнуться с такими особенностями OS/9, как проблемы с сетевыми компонентами. Проблема проявлялась в виде «подвисания» сетевого соединения в случае слишком интенсивной работы по нему. При этом работа по соединению уже не могла быть продолжена никаким способом – ни повторной установкой соединения, ни попыткой продолжения работы. Более того, в случае, если по такому «подвисшему» соединению продолжали посылать данные, то ОС полностью «подвисала», что делало невозможным даже её перезагрузку без вмешательства оператора. Ситуация возникала только в варианте OS/9 для платформы intel и только на некоторых версиях ОС.
Для устранения проблемы нам пришлось ввести несколько уровней защиты. Первый уровень заключался в распределении нагрузки. Мы пытались искусственно ограничивать пропускную способность канала. Второй уровень требовал постоянного ответа от партнёра по соединению – в случае, если в течение некоторого времени сообщения не приходили, наш драйвер сигнализировал управляющей программе о том, что необходимо переключиться на резервную линию связи и готовиться к перезагрузке рабочей станции. Введение этих мер позволило обеспечить своевременную диагностику и предотвращение неожиданных отказов ПО, выполнявшего критически важные функции.
Последней в списке (но далеко не последней по значимости) идёт операционная система QNX. С этой ОС мы знакомы с 1998 года (версия 4.23). Из всех вышеперечисленных ОС эта наиболее удобна, на наш взгляд, для разработки. Хотя в ней тоже были (и есть) некоторые особенности. Все они связаны с функционированием файловой системы.
Первая особенность, с которой мы столкнулись – родная файловая система не поддерживает файлы размером больше 2Гб. При этом есть одна интересная особенность – если писать файл размером ровно 2Гб, то последний байт не записывается (!). Если быть точным, то он записывается, но при считывании считывается на 1 байт меньше.
Вторая особенность заключается в том, что операции write и read, выполняемые для блочного файла и с границы в 512 байт блока, кратного 512 байтам (в нашем случае 4096), могут завершиться с указанием на факт считывания меньшего количества байт (кратного 512, но меньшего 4096). Это поведение не является ошибкой или нарушением требований того же posix, но является особенностью ОC QNX.
Третья особенность, с которой мы столкнулись — очень редкая ситуация, при которой операция write завершается с ошибкой нехватки памяти. Эта ошибка не предусмотрена ни в документации на QNX, ни в стандарте. Анализ исходного текста примера драйвера для QNX показал, что такая ситуация действительно возможна в случае нехватки оперативной памяти.
В настоящее время мы расширяем число ОС реального времени, в которых функционирует СУБД ЛИНТЕР. На данный момент мы заняты переносом системы на RTOS 32. Эта операционная система с WIN32-api интерфейсом. В этой ОС обнаруживалось некоторое количество ошибок, которые более или менее оперативно устраняются разработчиками. Однако пока мы не имеем окончательного результата и приводить какие-то данные по этой ОС рано.
Кроме новых операционных систем, мы продолжаем развивать СУБД. В этом году будут доработаны новые механизмы, которые найдут своё место в приложениях реального времени.
Основным нововведением в этом году будет аппарат хранимых событий. Этот аппарат позволит привязывать к конкретному временному событию (фиксированному или циклическому) наступление определённого события или запуск хранимой процедуры. Разумеется, все существующие возможности по ожиданию событий или их комбинации будет сохранены. События будут общими или персональными, будет обеспечено управление доступом к событиям и другие «вкусности».
Вторым по важности нововведением будет возможность управления процессом квантования выполнения запросов по времени и возможность использования функции задержки «sleep» в хранимых процедурах.
Третьим нововведением будет возможность автоматической аутентификации пользователя по имени пользователя, зарегистрированного в ОС. Эта возможность будет тоже настраиваться для различных пользователей.
Четвёртое нововведение – библиотека управления запуском и остановом СУБД, созданием базы данных, проверкой функционирования ядра и пр.
Наши планы на перспективу – модернизация ядра СУБД по технологии микроядра с возможностью «горячего» обновления отдельных модулей и возможностью наращивания функциональности без остановки СУБД.