Распределенные транзакции в Greenplum

Greenplum распределенные транзакции уровни изоляции ACID, архитектура данных, ACID в распределенных транзакциях, Greenplum Arenadata DB примеры курсы обучение, курсы по большим данным, курсы Big Data, обучение большим данным, обучение Big Data, Big Data Quality Management, курсы ИТ-архитекторов, Школа Больших Данных Учебный Центр Коммерсант

Недавно мы писали про трудности реализации ACID-требований к транзакциям в распределенных базах данных и способах их решения. Сегодня рассмотрим, как это работает в Greenplum с Arenadata DB: уровни изоляции, идентификаторы транзакций, моментальные снимки и MVCC-модель управления параллелизмом.

Как GP и Arenadata DB реализуют распределенные транзакции

Будучи основанной на PostgreSQL, Greenplum использует ее модель Multiversion Concurrency Control (MVCC) для управления одновременными транзакциями в таблицах кучи. Напомним, транзакция – это набор операций, между Begin и Commit/Abort, имеющие следующие ACID-свойства:

  • Atomicity (Атомарность)— выполняются либо все операции, либо ни одна из них. В случае сбоя или отмены последствия любой операции, принадлежащей транзакции, отменяются все, т.е. выполняется откат назад.
  • Consistency (Непротиворечивость) — каждая транзакция переводит систему из одного согласованного состояния в другое;
  • Isolation (Изоляция)– одновременное выполнение нескольких транзакций без влияния друг на друга за счет отсутствия фиксации промежуточных результатов всей транзакции до ее полного успешного завершения или отмены.
  • Durability (Долговечность) — устойчивость результатов выполнения транзакции после ее фиксации.

Чтобы одновременно выполнять несколько запросов, обеспечивая целостность данных, в СУБД используются специальные способы управления распределенными транзакциями, например, протокол двухфазной фиксации (2PC), концепции вложенных или компенсирующих транзакций (Saga). 2PC-протокол предотвращает изменение данных, которые были прочитаны другой параллельной транзакцией и блокирует чтение или запись любой данных, обновленных другой транзакцией. Такие блокировки снижают общую пропускную способность транзакций. Поэтому Greenplum, PostgreSQL и Arenadata DB используют MVCC-механизм для управления параллелизмом таблиц кучи, чтобы каждый запрос работал с моментальным снимком базы данных. Моментальный снимок (snapshot) — это набор строк, видимых в начале оператора или транзакции. Он гарантирует, что запрос имеет согласованное и действительное представление базы данных на время его выполнения. Таким образом, во время выполнения SQL-запрос не видит изменения, сделанные другими параллельными транзакциями, что обеспечивает согласованность данных. Запросы на чтение не блокируются в ожидании транзакций, записывающих строки. И наоборот, запросы на запись не блокируются транзакциями на чтение. Это обеспечивает больший параллелизм по сравнению с классическим 2PC-протоколом и повышает производительность СУБД. Подробнее о том, как Greenplum расширяет MVCC-модель PostgreSQL для управления доступом к данным в многопользовательской среде, обеспечивая согласованность и изоляцию транзакций для нескольких сегментов в большом кластере, читайте в нашей новой статье.

Справедливости ради стоит отметить, что AO-таблицы Greenplum и Arenadata DB, используют другую модель управления параллелизмом вместо MVCC, поскольку, в отличие от таблиц кучи, они предназначены для приложений с однократной записью и многократным чтением, что не предполагает обновления на уровне строк. Подробнее об этом мы рассказывали здесь и здесь.

Каждой транзакции в Greenplum и Arenadata DB присваивается уникальный идентификатор транзакции (XID) в виде автоинкрементального 32-битного значения. Поскольку XID имеет 32-хбитную разрядность, Greenplum может выполнить более 4-Х миллиардов транзакций, прежде чем это значение переполнится и обнулится. А благодаря очистке устаревших XID через каждые два миллиарда транзакций с помощью операции VACUUM их дублирование исключено. Если операция VACUUM не выполняется, Greenplum прекращает создание транзакций, чтобы избежать возможной потери данных.

Оператор SQL, не включенный в транзакцию, обрабатывается как транзакция с одним оператором — BEGIN и COMMIT добавляются неявно, что похоже на автоматическую фиксацию. Greenplum присваивает значения XID только транзакциям, которые включают операции определения данных (DDL) или манипулирования с ними (DML).

При транзакционной вставке строки, XID сохраняется вместе с ней в системном столбце xmin. При транзакционном удалении, XID сохраняется в системном столбце xmax. Обновление строки обрабатывается как удаление и вставка, поэтому XID сохраняется в xmax текущей строки и xmin новой вставленной строки. Столбцы xmin и xmax вместе со статусом завершения транзакции определяют диапазон транзакций, для которых отображается версия строки. Транзакция может видеть результаты всех транзакций меньше xmin, которые гарантированно будут зафиксированы, но не может видеть эффекты любой транзакции больше или равной xmax.

Транзакции с несколькими операторами записывают, какая команда внутри транзакции вставила (cmin) или удалила строку (cmax), чтобы вся транзакция могла видеть изменения, сделанные предыдущими командами в ней. Последовательность команд актуальна только во время транзакции, поэтому в начале каждой транзакции эта последовательность сбрасывается на 0.

Каждая база данных сегмента Greenplum имеет свою собственную последовательность XID, которую нельзя сравнивать с XID других баз данных сегмента. Координатор координирует распределенные транзакции с сегментами, используя gp_session_id — идентификатор сеанса для всего кластера. Сегменты поддерживают сопоставление распределенных идентификаторов транзакций с их локальными XID. При этом координатор управляет распределенными транзакция по сегменту с помощью 2PC-протокола. В случае сбоя транзакции в каком-то одном сегменте Greenplum, она откатывается во всех сегментах. Так обеспечивается согласованность данных в распределенной системе.

4 уровня изоляции транзакций и их поддержка в Greenplum

На уровне стандарта SQL принято выделять 4 уровня изоляции транзакций:

  • Read uncommited — чтение незафиксированных данных;
  • Read committed – чтение зафиксированных данных;
  • Repeatable read – повторяемое чтение;
  • Serializable – сериализуемость, т.е. параллельное выполнение набора транзакций, которое гарантированно дает тот же эффект, что и их последовательное выполнение по одной.

Serializable является самым строгим уровнем изоляции транзакций без каких-либо взаимодействий между ними. В остальных уровнях могут происходить такие недопустимые явления, как  грязное чтение, когда транзакция считывает данные, записанные параллельно незафиксированной транзакцией, неповторяемое чтение, когда транзакция повторно считывает данные, которые она ранее читала, и обнаруживает, что они были изменены другой транзакцией, зафиксированной с момента первоначального чтения. Также к нарушениям строгой изоляции, которые случаются на Read uncommited и Read committed относят фантомное чтение, когда транзакция повторно выполняет запрос, возвращающий набор строк, удовлетворяющих условию поиска, и обнаруживает, что он изменился из-за другой недавно зафиксированной транзакции. Наконец, изоляцию нарушает аномалия сериализации, когда результат успешной фиксации группы транзакций несовместим со всеми возможными порядками их выполнения по одной за раз.

Уровень изоляции

Грязное чтение (Dirty Read)

Неповторяемое чтение (Non-Repeatable)

Фантомное чтение (Phantom Read)

Аномалия сериализации (Serialization Anomoly)

READ UNCOMMITTED

Разрешено, но не в Greenplum

Возможно

Возможно

Возможно

READ COMMITTED

Невозможно

Возможно

Возможно

Возможно

REPEATABLE READ

Невозможно

Невозможно

Разрешено, но не в Greenplum

Возможно

SERIALIZABLE

Невозможно

Невозможно

Невозможно

Невозможно

Greenplum реализует только два уровня изоляции транзакций, хотя разработчик приложения может запросить любой возможных. Уровень READ UNCOMMITTED в Greenplum реализуется READ COMMITTED, а уровень SERIALIZABLE – как REPEATABLE READ. Причем реализация REPEATABLE READ в Greenplum не допускает фантомного чтения. Справедливости ради стоит отметить, что некоторые типы данных и функции Greenplum имеют специальные правила поведения транзакций. В частности, изменения, внесенные в последовательность и в счетчик столбца, объявленный с помощью serial, немедленно видны всем другим транзакциям и не откатываются назад при прерывании транзакции, в которой были внесены изменения.

По умолчанию Greenplum использует уровень изоляции READ COMMITTED, когда SQL-запрос на выборку данных с оператором SELECT без предложения FOR UPDATE/SHARE видит только данные, зафиксированные до начала запроса. По сути, этот запрос SELECT видит моментальный снимок базы данных в момент начала выполнения запроса. Но запрос SELECT также видит результаты предыдущих обновлений, выполненных в рамках его собственной транзакции, даже если они еще не зафиксированы. Две последовательные команды SELECT могут видеть разные данные, даже если они находятся в одной транзакции, если другие транзакции фиксируют изменения после запуска первой команды SELECT и до начала второй команды SELECT.

Из-за этого команда UPDATE может видеть несогласованный моментальный снимок. Такое поведение делает режим READ COMMITTED непригодным для команд со сложными условиями поиска, но подходит для более простых случаев. Приложениям, выполняющим сложные запросы и обновления, может потребоваться более строго согласованное представление базы данных, чем обеспечивает уровень изоляции READ COMMITTED.

Уровень изоляции REPEATABLE READ видит только данные, зафиксированные до начала транзакции и последствия предыдущих обновлений, выполненных в рамках его собственной транзакции, даже если они еще не зафиксированы. Этот уровень изоляции отличается от READ COMMITTED тем, что запрос в транзакции REPEATABLE READ видит моментальный снимок в момент начала первого оператора, а не текущего оператора транзакции. Последовательные команды SELECT в рамках одной транзакции видят одни и те же данные, без изменений, сделанных другими транзакциями, зафиксированными после запуска их собственной.

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

Таким образом, уровень REPEATABLE READ обеспечивает строгую гарантию того, что каждая транзакция видит полностью стабильное представление базы данных. Но это представление не обязательно всегда будет соответствовать последовательному выполнению параллельных транзакций одного уровня. Поэтому с таким уровнем изоляции часто применяются явные блокировки конфликтующих транзакций.

Уровень SERIALIZABLE не поддерживается Greenplum и аналогичен уровню REPEATABLE READ. В этой MPP-СУБД модель MVCC предотвращает грязное чтение, неповторяемое чтение и фантомное чтение без дорогостоящей блокировки, но не обеспечивает полную сериализуемость транзакций. Такие аномалии часто случаются из-за того, что Greenplum не выполняет блокировку предикатов, т.е. запись в одной транзакции может повлиять на результат предыдущего чтения в другой параллельной транзакции.

Уровень изоляции транзакций для базы данных Greenplum по умолчанию задается для всех транзакций в сеансе и указывается в параметре конфигурации сервера default_transaction_isolation. Чтобы установить уровень изоляции для текущей транзакции, можно использовать команду SQL SET TRANSACTION. Следует обязательно устанавливать уровень изоляции перед любой инструкцией SELECT, INSERT, DELETE, UPDATE или COPY:

BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
...
COMMIT;

Также можно указать режим изоляции в самом операторе BEGIN:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Узнайте больше про администрирование и эксплуатацию Greenplum с Arenadata DB для эффективного хранения и аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Источники

  1. https://docs.vmware.com/en/VMware-Tanzu-Greenplum/7/greenplum-database/GUID-admin_guide-intro-about_mvcc.html
  2. https://docs.arenadata.io/adb/adminguide/concurcont.html
  3. https://learn.microsoft.com/ru-ru/sql/odbc/reference/develop-app/transaction-isolation-levels?view=sql-server-ver16
Поиск по сайту