В распределенной базе данных конфликт репликации возникает при одновременном (условно) изменении одной записи в результате выполнения транзакций разными серверами над локальными репликами. Однако конфликт будет обнаружен только при синхронизации данных. Все распределенные СУБД идентифицируют конфликты, но не всегда могут обеспечить автоматическое их устранение - отмену всех изменений или применение одного из них, т.к. эта задача требует вмешательства человека (администратора) из-за необходимости учета специфики назначения и структуры данных, конкретных значений, объектов и характера конфликта. Эффективность разрешения конфликтов, а с другой стороны - потери из-за отказов в выполнении запросов к заблокированным объектам базы данных зависят от функциональных и эксплуатационных характеристик предоставляемого администратору инструментария СУБД.
Обработка конфликтов репликации в СУБД Oracle
В СУБД Oracle при возникновении конфликтной транзакции соответствующие данные помещаются в системную таблицу system.def$_aqerror. Основными полями, описывающими конфликтные транзакции, являются [2]:
Значение поля USER_DATA представляет собой массив байт, для хранения которого в Oracle используется тип BLOB. Байты в массиве располагаются следующим образом (рис. 1). Первый байт определяет тип аргумента, над которым пользователем были произведены изменения. Каждому типу аргумента соответствует определенное количество байт. Следующий байт определяет количество байт, в соответствие с указанным типом аргумента, в которых закодированы изменения аргумента пользователями. Далее в указанном количестве байт содержится информация об исходном значении аргумента до внесения изменений пользователями. Следующая группа байт такого же размера содержит модифицированное значение аргумента. Таким образом, алгоритм сводится к последовательному разбору массива байт, хранящегося в поле USER_DATA по каждому вызову в конфликтной транзакции. Текущее значение изменяемого аргумента определяется непосредственно из БД по SQL-запросу.
Рис. 1. Массив байт поля USER_DATA.
Таким образом, каждая транзакция содержит в себе определённое количество вызовов, которые в свою очередь содержат набор аргументов. Количество аргументов зависит от определённой таблицы, над которой были произведены действия пользователем, и если количество полей в таблице велико, то соответственно количество аргументов также будет большим.
Разработчиками СУБД Oracle предлагается администратору баз данных использовать функционал приложения Oracle Enterprise Manager (OEM) для разрешения конфликтных транзакций [5]. ОЕМ последовательно извлекает конфликтные транзакции из очереди и выполняет их разбор при помощи системного (для СУБД Oracle) пакета dbms_defer_query. Полученная в результате разбора информация отображается для принятия решения администратором БД, после чего конфликтная транзакция удаляется из очереди. Общий алгоритм разбора конфликтной транзакции в ОЕМ показан на рис. 2.
Разбор конфликтных транзакций в OEM реализован при помощи пакета dbms_defer_query. Данный пакет содержит следующие функции, которые позволяют получать данные, необходимые для разбора вызовов в конфликтных транзакциях [5]:
Текущее значение данных изменяемой таблицы определяется непосредственно путём обращения к таблице и считывания необходимых данных по каждому аргументу вызова конфликтной транзакции.
Языком разработки OEM является Java. В отличие от многих языков программирования, Java - это еще и программная платформа, включающая большой объём кода мощной библиотеки и среду для выполнения программ (Java Virtual Machine), которая обеспечивает безопасность, независимость от операционной системы и автоматическую «сборку мусора».
В руководстве по языку Java декларируются такие его свойства, как: простой, объектно-ориентированный, распределённый, надёжный, безопасный, независимый от архитектуры компьютера, переносимый, интерпретируемый, высокопроизводительный, многопотоковый, динамичный [3]. Такие характеристики, как независимость от архитектуры компьютера и производительность, требуют более подробного рассмотрения.
Компилятор Java генерирует объектный файл, формат которого не зависит от архитектуры компьютера. Объектный файл содержит байтовый код, разработанный таким образом, чтобы его можно было легко интерпретировать с помощью виртуальной машины [4]. Интерпретация байтового кода всегда будет выполняться медленнее, чем выполнение эквивалентного машинного кода. Однако на многих платформах возможна так называемая синхронная компиляция (just-in-time compilers - JIT) байтового кода, но даже в этом случае в итоге не обеспечивается такая же производительность, как при компиляции, ориентированной на конкретный тип процессора [3].
Рис. 2. Блок-схема разбора вызовов в OEM.
Таким образом, независимость от архитектуры компьютера является в то же время и слабой стороной Java, обуславливающей снижение производительности программ, разработанных на этой платформе. Тот факт, что OEM разработан на Java, является одним из факторов, снижающих производительность этого ПО.
Выполнение различных операций в OEM сопровождается множеством фоновых задач, выполняемых JVM, что существенно увеличивает время получения результата. Взаимодействие OEM с базой данных осуществляется посредством JDBC (Java Database Connectivity - интерфейс взаимодействия Java-приложений с базами данных) [5].
Для разрешения конфликтных транзакций в распределённой БД необходимо получить список конфликтных транзакций и детальную информацию по каждому вызову транзакции. Это реализуется посредством вызова упомянутых выше функций, исполняемых JVM, которая формирует ряд SQL-запросов к конкретной БД и получает результат их выполнения. После выполнения обработки полученной информации по заложенным в OEM алгоритмам JVM выполняет преобразование информации в удобочитаемую форму.
При таком взаимодействии OEM и JVM наиболее критическими факторами с точки зрения производительности являются следующие:
Альтернативный способ разбора конфликтных транзакций
Описанные выше проблемы, свойственные OEM, устраняются при использовании утилиты ErrManager, разработанной автором в среде Embarcadero Delphi. ErrManager получает необходимые данные из БД путём SQL-запросов. Время получения данных ограничено только загруженностью БД и связью между клиентской машиной и сервером БД, а разбор конфликтной транзакции осуществляется на стороне клиента с существенно меньшим, в отличие от OEM, использованием ресурсов сервера БД [1]. Алгоритм разбора показан на рис. 3.
Рис. 3. Блок схема разбора вызовов в ErrManager.
ErrManager разбирает BLOB-значения без использования системного пакета dbms_defer_query, тем самым получая необходимые исходные значения изменяемых объектов БД. Это значительно снижает время получения старых, новых и текущих значений за счёт снижения количества и сокращения времени обращений к БД, тем самым значительно уменьшая время разрешения конфликта.
Таким образом, на основе анализа выше описанного алгоритма разбора вызовов в конфликтных транзакциях можно заключить, что время разбора значительно сокращается за счёт того, что для каждого вызова в транзакции анализируется фактически только однократно извлекаемое значение поля USER_DATA таблицы system.def$_aqerror. Разбор массива байт путём считывания и преобразования в число или текст является более эффективным и не требует использования ресурсов БД, по сравнению с повторяющимися многократно вызовами набора функций из системного пакета при разборе вызовов в OEM.
Разработанная утилита ErrManager имеет вид приложения пользователя (рис. 4).
Рис. 4. Общий вид приложения ErrManager.
Функции, реализованные в утилите ErrManager, позволяют [1]:
Заключение
Проведенное тестирование утилиты ErrManager включало в себя временную оценку процесса разрешения конфликтных транзакций и синхронизации данных при реплицировании информации между различными узлами распределённой БД. Результаты тестирования показали, что использование ErrManager является более эффективным по сравнению с Oracle Enterprise Manager.
Рецензенты