exam16 2 - stankin/design-part-1 GitHub Wiki

! В заголовке нужно привести полный текст вопроса

Простые и распределенные транзакции.

Введение

Транзакция -- это основная логическая единица работы с данными в СУБД. В большинстве случаев СУБД работает асинхронно, а это означает, что она должна работать корректно с множеством потоков, обращающихся к ней независимо. Это характеризуется соответствием принципу ACID (Atomicity, Consistency, Isolation, Durability).

Атомарность (Atomicity): каждая транзакция должна выполняться как единое действие или не выполняться вообще.

Согласованность (Consistency): При совершении транзакции система должа соответствующим образом менять свое состояние.

Изоляция (Isolation): Все транзакции, происходящие одновременно не должны влиять друг на друга.

Долговечность (Durability): Если транзакция произошла, то ее результат не должен быть изменен при аварийной остановке работы СУБД.

Обычные транзакции

Каждое действие с СУБД, связанное с изменением данных -- это транзакция. Простейшее описание транзакции выглядит так:

  1. Начало транзакции
  2. Выполнение необходимых операций или запросов
  3. В случае, если ошибок не произошло, подтвердить транзакцию
  4. В ином случае откатить транзакцию вместе со всеми операциями, выполненными в п. 2

В идеале транзакции разных пользователей должны выполняться так, чтобы создавалась иллюзия, что пользователь текущей транзакции — единственный. Однако в реальности, по соображениям производительности и для выполнения некоторых специальных задач, СУБД предоставляют различные уровни изоляции транзакций.

Уровни описаны в порядке увеличения изолированности транзакций и, соответственно, надёжности работы с данными.

0 — Чтение неподтверждённых данных (Read Uncommitted) — чтение незафиксированных изменений как своей транзакции, так и параллельных транзакций. Нет гарантии, что данные, изменённые другими транзакциями, не будут в любой момент изменены в результате их отката, поэтому такое чтение является потенциальным источником ошибок. Невозможны потерянные изменения (lost changes), возможны грязное чтение (dirty read), неповторяемое чтение и фантомы.

1 — Чтение подтверждённых данных (Read Committed) — чтение всех изменений своей транзакции и зафиксированных изменений параллельных транзакций. Потерянные изменения и грязное чтение не допускается, возможны неповторяемое чтение и фантомы.

2 — Повторяемое чтение (Repeatable Read, Snapshot) — чтение всех изменений своей транзакции, любые изменения, внесённые параллельными транзакциями после начала своей, недоступны. Потерянные изменения, грязное и неповторяемое чтение невозможны, возможны фантомы.

3 — Сериализуемый (Serializable) — сериализуемые транзакции. Результат параллельного выполнения сериализуемой транзакции с другими транзакциями должен быть логически эквивалентен результату их какого-либо последовательного выполнения. Проблемы синхронизации не возникают.

Чем выше уровень изоляции, тем больше требуется ресурсов, чтобы его обеспечить. Соответственно, повышение изолированности может приводить к снижению скорости выполнения параллельных транзакций, что является «платой» за повышение надёжности. [1]

Полноценная реализация уровней изоляции и свойств ACID представляет собой нетривиальную задачу. Обработка поступающих данных приводит к большому количеству маленьких изменений, включая обновление как самих таблиц, так и индексов. Эти изменения потенциально могут потерпеть неудачу: закончилось место на диске, операция занимает слишком много времени и т. д. Система должна в случае неудачи корректно вернуть базу данных в состояние до транзакции.

Первые коммерческие СУБД (к примеру, IBM DB2), пользовались исключительно блокировкой доступа к данным для обеспечения свойств ACID. Но большое количество блокировок приводит к существенному уменьшению производительности. Есть два популярных семейства решений этой проблемы, которые снижают количество блокировок:

  • журнализация изменений (write ahead logging, WAL)
  • механизм теневых страниц (shadow paging)

С развитием технологий параллельного программирования и управления базами данных появились неблокирующие методы доступа к данным и их изменения. Идея контроля над параллельным доступом с помощью временных меток (timestamp-based concurrency control) была развита и привела к появлению многоверсионной архитектуры MVCC. Эти технологии не нуждаются ни в журнализации изменений, ни в теневых страницах. Архитектура, реализованная в Oracle 7.х и выше, записывает старые версии страниц в специальный сегмент отката, но они все ещё доступны для чтения. Если транзакция при чтении попадает на страницу, временная метка которой новее начала чтения, данные берутся из сегмента отката (то есть используется «старая» версия). Для поддержки такой работы ведётся журнал транзакций, но в отличие от «упреждающей журнализации», он не содержит данных. Работа с ним состоит из трёх логических шагов:

1. Записать намерение произвести некоторые операции
2. Выполнить задание, копируя оригиналы изменяемых страниц в сегмент отката
3. Записать, что всё сделано без ошибок

Журнал транзакций в сочетании с сегментом отката (область, в которой хранится копия всех изменяемых в ходе транзакции данных) гарантирует целостность данных. В случае сбоя запускается процедура восстановления, которая просматривает отдельные его записи следующим образом:

1. Если повреждена запись, то сбой произошёл во время проставления отметки в журнале. Значит, ничего важного не потерялось, игнорируем эту ошибку.
2. Если все записи помечены как успешно выполненные, то сбой произошёл между транзакциями, здесь также нет потерь.
3. Если в журнале есть незавершённая транзакция, то сбой произошёл во время записи на диск. В этом случае мы восстанавливаем старую версию данных из сегмента отката.

Firebird вообще не имеет ни журнала изменений, ни сегмента отката, а реализует MVCC, записывая новые версии строк таблиц прямо в активное пространство данных. Так же поступает MS SQL. Теоретически это даёт максимальную эффективность при параллельной работе с данными, но ценой является необходимость «сборки мусора», то есть удаления старых и уже не нужных версий данных. [2]

В языке SQL существует механизм проведения составных транзакций, т. е. транзакций, состоящих из нескольких действий. Он представляется следующими ключевыми словами:

  • COMMIT (Сохраняет изменения)
  • ROLLBACK (Откатывает изменения)
  • SAVEPOINT (Создаёт точку к которой группа транзакций может откатиться)
  • SET TRANSACTION (Объявляет имя транзакции)

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

Распределенная транзакция -- это транзакция, в которой участвуют 2 или более хоста с БД. Как и обычные транзакции, они также должны соответствовать принципу ACID. OpenGroup, будучи ассоциацией вендоров, предложила модель X/Open Distributed Transaction Processing (DTP) Model (X/Open XA), которая стала де-факто стандартом для описания модели распределенных транзакций.

Реализация распределенных транзакций сложна из-за того, что характер распределенной системы не позволяет должным образом обеспечить изоляцию. Из-за задержек сети, оборудования и ПО, необходимо создавать новый механизм обеспечения глобальной сериализации данных. В качестве такого механизма обычно используют strong strict two phase locking (SS2PL).

Распространенным алгоритмом распределенных транзакций является two-phase commit (2PC). Он используется для проведения небольших быстрых транзакций. Для более долгих распределенных транзакций используется паттерн Compensating Transaction, в рамках которого реализуется отдельная транзакция для отката набора уже выполненных транзакций. [3]

Список источников

  1. https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)#%D0%A3%D1%80%D0%BE%D0%B2%D0%BD%D0%B8_%D0%B8%D0%B7%D0%BE%D0%BB%D1%8F%D1%86%D0%B8%D0%B8_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B9
  2. https://ru.wikipedia.org/wiki/%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D1%8F_(%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)#%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F
  3. https://en.wikipedia.org/wiki/Distributed_transaction
! Указание источников обязательно (лучше делать ссылки прямо в тексте)