Дэниел Абади и Александер Томсон
Перевод: Сергей Кузнецов
Оригинал: Daniel Abadi, Alexander Thomson. The Case for Determinism in Database Systems. 36th International Conference on Very Large Data Bases, September 13-17, 2010, Singapore. Proceedings of the VLDB Endowment, Vol. 3, No. 1, 2010, pp. 70-80.
В области транзакционных систем управления данными в новых средах, обеспечивающих простое горизонтальное масштабирование массивно-параллельных аппаратных средств (в частности, в "облачных" средах), продолжается борьба двух направлений. Первое из них ориентируется на обеспечение повышенных уровней масштабируемости и доступности за счет отказа от некоторых из свойств ACID транзакций. Представители второго направления стремятся полностью сохранить свойства ACID и добиться масштабируемости и доступности за счет, например, отказа от работы с дисковой памятью (т.е. в их системах базы данных поддерживаются только в основной памяти).
В обоих направлениях ведутся активные исследовательские (и даже производственные) работы, и регулярно публикуются интересные статьи. Чтобы не повторяться, сошлюсь на перечень переведенных на русский язык статей, авторов которых, скорее, можно отнести к лагерю "NoACID". Этот перечень содержится в моей вступительной заметке к ранее переведенной статье.
В направлении исследований транзакционных систем нового поколения наиболее известным является проект H-Store, в котором участвуют специалисты Массачусетского технологического института, Йельского университета, университета Браун и HP Labs. Общеизвестно, что этот проект были инициирован Майклом Стоунбрейкером (Michael Stonebraker), и на основе его начальных результатов при активнейшем участии того же Стоунбрейкера была создана компания VoltDB, первая версия коммерческого продукта которой была выпущена в самом конце весны 2010 г.
Однако это вовсе не означает конца работы над проектом H-Store. В начальной версии прототипа системы поддерживался только достаточно узкий класс транзакций, недостаточно были проработаны возможности горизонтального масштабирования системы. Участники проекта активно ищут новые методы управления транзакциями, которые позволили бы расширить круг возможных применений системы и добиться при этом не меньших уровней доступности и масштабируемости, чем те, которые обеспечиваются в системах NoACID. Очень интересная статья была опубликована в Трудах конференции SIGMOD'2010.
В Трудах недавно прошедшей конференции VLDB'2010 опубликованы еще две статьи участников проекта: статья Абади и Томсона из Йельского университета, перевод которой вам предлагается в этот раз, и статья группы авторов из MIT, которую я также вскоре собираюсь перевести. Хотя на VLDB'2010 эти две статьи были поданы вне прямой связи с H-Store, я думаю, что какие-то результаты почти наверняка будут использованы в этом проекте.
В статье Абади и Томсона описывается подход к управлению транзакциями, при котором удается приблизиться к желательным уровням доступности и масштабируемости массивно-параллельных тразакционных систем за счет отказа от недетерминированного планирования транзакций. Описываются результаты теоретических и экспериментальных исследований, выполненных на очень высоком уровне. Вместе с тем, текст статьи нельзя считать идеальным: многие важные аспекты описаны "скорописью", некоторые важные выводы недостаточно обоснованы и т.д. Возможно, это связано с тем, что Александер Томсон (который, скорее всего, и писал статью) – всего лишь аспирант второго года обучения, и эта статья – первая в его жизни. Думаю, что для первого раза результат можно считать просто блестящим.
Так что прошу вас не обращать внимание на технические погрешности статьи, а постараться понять ее суть. Возможно, именно этот подход станет основой будущих транзакционных СУБД.
Сергей Кузнецов
В этой статье мы предлагаем подход к организации распределенной системы баз данных, в котором техника предупреждения тупиковых синхронизационных ситуаций объединяется со схемами управления параллелизмом, гарантирующими эквивалентность некоторому предопределенному порядку выполнения транзакций. По существу, это устраняет недетерминизм из типичных рабочих нагрузок категории OLTP, позволяя производить активную репликацию без каких-либо накладных расходов на синхронизацию. Кроме того, в нашей системе отсутствует потребность в двухфазной фиксации каких бы то ни было распределенных транзакций, даже таких, которые распространяются на несколько узлов в пределах одной реплики. За счет отсутствия потребности в выявлении тупиковых ситуаций и двухфазной фиксации для многих рабочих нагрузок наша система превосходит по производительности традиционные системы допускающие недетерминированное переупорядочивание транзакций.
Недетерминированное поведение в системах баз данных приводит к трудностям при реализации репликации баз данных и горизонтально масштабируемых распределенных баз данных. Обсудим эти проблемы по порядку.
Последствием использования недетерминированных протоколов управления параллелизмом является то, что два сервера с идентичным программным обеспечением управления базами данных и одним и тем же исходным состоянием баз данных при получении одинаковых последовательностей запросов на образование транзакции могут перевести свои базы данных в совершенно разные состояния. В схемах репликации обычно предусматриваются предосторожности, предотвращающие или ограничивающие такие расхождения. Желательно, чтобы схема репликации отвечала трем следующим требованиям:
Поскольку в современных системах баз данных допускается недетерминированное поведение, схемы репликации обычно основываются на компромиссе между согласованностью, корректностью и низкими накладными расходами. Распространенные схемы репликации обычно относятся к одному из следующих трех семейств, различаясь деталями и стоимостью:
Репликация после записи (post-write replication). Здесь записи сначала выполняются над одной репликой, а репликация происходит после завершения записей. К этой категории относится традиционная репликация "ведущий-подчиненный" (master-slave), где все транзакции выполняются основной "ведущей" системой, наборы записи (write set) которой затем передаются во все "подчиненные" системы с репликами, обновляющие данные в том же порядке, чтобы обеспечить сближение своего результирующего состояния с состоянием базы данных ведущей системы. Обычно это реализуется на основе "пересылки журнала" (log shipping) [14, 20] – ведущая система рассылает журнал транзакций, который воспроизводится подчиненными системами над каждой репликой.
Эта категория также включает схемы, в которых для разных элементов данных имеются разные ведущие системы, а также вариации на эту тему, в которых разные узлы могут получать "арендные договора" ("lease"), делающие их ведущими для некоторого конкретного элемента данных. В этих случаях при обработке транзакций, которые затрагивают данные более чем одной ведущей системы, требуется некоторый сетевой коммуникационный протокол (например, протокол двухфазной фиксации), обеспечивающий согласованность реплик. Если используются протоколы управления параллелизмом, основанные на блокировках, то необходимо еще и выявлять распределенные тупиковые ситуации.
При применении и традиционной схемы репликации "ведущий-подчиненный", и ее вариантов, когда для разных данных ведущими являются разные узлы, записи сначала выполняются в ведущем узле, и данные реплицируются после их завершения. Уровень отставания реплик от основных данных зависит от скорости, с которой подчиненные узлы применяют наборы записи ведущего узла, но всегда имеется хотя бы незначительное отставание. Поэтому не гарантируется, что в ответ на запросы по чтению, направляемые в подчиненные узлы, будут выдаваться "свежие" результаты, если только не заставлять приложения ждать, пока подчиненные узлы "не наверстают упущенное" (для некоторых приложений это допустимо) [22. 19, 2].
Кроме того, в системах с репликацией после записи имеется фундаментальная взаимозависимость между величиной задержки, долговечностью (durability) транзакций и согласованностью реплик. Если ведущий узел не фиксирует транзакции до получения подтверждения о получении подчиненными узлами пересланных им данных, то возрастает задержка. В противном случае, если в ведущем узле возникает отказ, журнальные записи, переданные перед этим в подчиненные узлы, могут до них не дойти. В этом случае либо теряются практически полностью выполненные транзакции, что плохо влияет на свойство долговечности, либо они воспроизводятся после восстановления работоспособности отказавшего узла, но транзакции, выполнявшиеся в это время в подчиненных узлах, нарушают согласованность.
Активная репликация с использованием синхронизированных блокировок (active replication with synchronized locking). В этом случае все узлы, содержащие реплики, должны договориться о блокировках по записи, которые должны накладываться на элементы данных [4]. Поскольку записи могут происходить только при наличии согласованной монопольной блокировки, во всех узлах, содержащих реплики, обновления будут происходить некоторым образом, эквивалентным такому же последовательному порядку, что гарантирует согласованность реплик. Недостатком этой схемы является дополнительная задержка, вызываемая сетевыми комуникациями для обеспечения синхронизации на основе блокировок. По этой причине такая схема на практике используется намного реже схем с репликацией после записи.
Репликация с отложенной синхронизацией (replication with lazy synchronization). Транзакции выполняются независимо в нескольких активных узлах, содержащих реплики (которые, возможно, временно рассогласуются), а позже их состояния синхронизуются [10, 7, 17]. Схемы с отложенной синхронизацией обеспечивают хорошую производительность за счет (временной) утраты согласованности реплик.
Если бы система баз данных могла выполнять последовательности поступающих транзакций полностью детерминированным образом, то можно было бы полностью избежать компромиссов между описанными выше желательными свойствами. Транзакции можно было бы заранее упорядочивать на некотором центральном сервере (или путем использования некоторой распределенной службы [18, 24]), а затем направлять их пакетами в каждый узел, содержащий реплики, для детерминированного выполнения. Это будет гарантировать, что в каждом из этих узлов результирующее состояние реплики будет согласовано с состояниями всех других реплик, и не потребуются накладные расходы для достижения каких-либо дополнительных соглашений или синхронизации.
Для обеспечения гарантий ACID в системах распределенной обработки транзакций в большинстве случаев используется распределенный протокол фиксации, обычно двухфазный. Такой протокол предназначен для сбора решений всех участвующих узлов о фиксации или аварийном завершении транзакции и гарантирования того, что достигнуто единое решение – даже несмотря на то, что во время выполнения протокола участвующие узлы могут выходить из строя. Накладные расходы на выполнение этих двух фаз протокола фиксации (а также дополнительное время, требуемое для удержания блокировок) снизить потенциально достижимую транзакционную пропускную способность разделенной системы. Это препятствие на пути к достижению высокой производительности привело к использованию технологий, ослабляющих свойства ACID (а именно, атомарность (atomicy) или изоляцию (isolation) транзакций) с целью получения масштабируемых распределенных систем баз данных (например, многих так называемых "NoSQL"-систем).
В детерминированных системах баз данных, основанных на использовании активной репликации, требуется использовать всего лишь однофазный протокол фиксации. Так получается из-за того, что в узлах, содержащих реплики, транзакции выполняются параллельно, так что отказ одной реплики не влияет на результирующее решение о фиксации или аварийном завершении транзакции. Поэтому не требуются дополнительные действия, предусматриваемые в двухфазном протоколе для обеспечения соответствующего выполнения при наличии потенциальной возможности отказа узла. Для транзакций, в которых отсутствует возможность нарушения ограничений целостности или возникновения других условий, приводящих к аварийному завершению, потребность в распределенном протоколе фиксации устраняется полностью (поскольку невозможны непредвиденные события типа возникновения тупиковой ситуации, приводящие к недетерминированному аварийному завершению транзакций). Тем самым, использование детерминированной схемы выполнения уменьшает, а для некоторых транзакций полностью устраняет наиболее значительную преграду на пути к созданию выскопроизводительных распределенных транзакционных систем.
Кроме того, мы реализуем прототип системы баз данных с использованием своей схемы детерминированного выполнения, а также (для сравнения) другой схемы, поддерживающей традиционные выполнение и протокол управления параллелизмом (двухфазный протокол блокировок). Сравнительное тестирование нашего начального прототипа на одной системе (без учета репликации), сопровождавшееся аналитическим моделированием, показывает, что при использовании современной аппаратуры соотношение показателей производительности детерминированного и недетерминированного решений значительно изменяется. Детерминированная схема обеспечивает значительно более низкую пропускную способность, чем традиционные схемы, при наличии долгих задержек при выполнении транзакции (возникающих, например, из-за чтения страницы с диска). Однако по мере того, как транзакции становятся короче и меньше различаются по длине, детерминированная схема приводит к почти полному исчезновению накладных расходов (разд. 3 и 4). Поэтому мы приходим к выводу, что следует пересмотреть проектные решения, допускающие недетерминизм.
Мы также проанализировали характеристики производительности своей детерминированной схемы выполнения в случае, когда данные разделяются по нескольким машинам (разд. 5). Мы установили, что на рабочих нагрузках, содержащих транзакции, которые затрагивают несколько разделов, наш прототип превосходит по производительности системы, основанные на традиционном блокировочном управлении параллелизмом и двухфазной фиксации.
Простейшим способом, за счет которого протокол управления параллелизмом мог бы гарантировать эквивалентность некоторому порядку выполнения {T0, T1, ..., Tn, было бы устранение всякого параллелизма и выполнение транзакций по очереди в указанном порядке. Однако при наличии современных многоядерных машин схемы, допускающие простой большей части процессоров, очевидно, приводят к неоптимальному использованию компьютерных ресурсов и, соответственно, плохой производительности.
К счастью, можно использовать блокировки, чтобы допустить некоторую параллельность, по-прежнему гарантируя эквивалентность предопределенному порядку следования. Эквивалентности предопределенному порядку следования (равно как и освобождения от тупиковых ситуаций) можно достичь путем ограничения набора допустимых планов выполнения теми, которые обладают следующими свойствами:
На практике упорядоченное блокирование обычно реализуется таким образом, что от транзакций требуется запрос всех блокировок сразу после входа в систему, хотя существуют классы транзакций, для которых это может оказаться невозможным. Мы подробно анализируем эти случаи в подразделе 4.2. Однако для целей сравнения, описываемого в следующем разделе, мы рассматриваем очень упрощенную реализацию такой схемы.
1 Это известный метод предупреждения тупиковых ситуаций. Примером системы, в которой блокировки производятся таким образом, является Postgres-R [13].
2 В некоторых ситуациях – например, в тех случаях, когда транзакция детерминированным образом застопоривается – может оказаться разумным временно переключиться на традиционную схему выполнения и репликации. Нахождение бесшовной модели переключения "на лету" моделей выполнения может стать увлекательным предметом будущих исследований.