Здравствуйте, меня зовут Дмитрий Карловский и я.. стараюсь сложные вещи рассказывать простым языком, а простые вещи — эзоповым. И часто оказывается так, что в процессе упрощения и структурирования, на самом видном месте обнаруживаются скелеты древних динозавров, присыпанные мутными формулировками так, что долгие годы их никто не замечает. Что ж, если вы хотите окончательно разобраться в уровнях изоляции транзакций и гарантиях порядка операций, до давайте копать вместе.
Данная классификация является непротиворечивым переосмыслением известной классификации от Jepsen в более краткой и ясной форме.

Как читать диаграмму:
На ней представлены модели памяти и феномены, которые они не допускают.
Все модели разделены на 2 ортогональные группы: одни определяют порядок операций, а другие уровень изоляции транзакций.
-
Все модели классифицированы по уровню доступности при разделении сети в распределённой системе:
Total Available — гарантии обеспечиваются на любом узле.
Sticky Available — гарантии обеспечиваются, если не переключаться между узлами.
Unavailable — часть или все узлы не смогут обеспечивать гарантии.
Формальная запись таймлайнов
Запись данных версии 5 в состояние S:
5=>S
Запись значения состояния X в состояние Y:
X=>Y
Запись в состояние S нового значения, основанного на его версии 5:
5+=>S
Чтение состояния S с получением данных версии 6:
S=>6
История операций, где Y шла после X:
X | Y
Истории операций X и Y двух агентов, происходящих параллельно:
X
Y
Истории операций X и Y двух агентов, происходящих последовательно:
X |
| Y
История операций X и Y в рамках одной успешной транзакции:
[ X | Y ]
История операций X и Y в рамках одной отменённой транзакции:
{ X | Y }
Общие определения
Агент — активный субъект, исполняющий прикладную логику.
Узел — пассивный субъект, обеспечивающий доступ к данным.
В клиент-серверной архитектуре узлом является инстанс субд, а агентом - её клиент. В одноранговой архитектуре каждый агент является узлом сети.
Гарантии порядка операций
Операция — атомарное действие, которое нельзя разбить на последовательность более мелких действий.
Monotonic
Монотонность — гарантия, что время движется только вперёд, без каких-либо откатов состояния.
Следующие феномены не допускаются:
Chaotic Read
Хаотичное чтение — феномен путешествия назад во времени, когда очередное чтение одного и того же состояния возвращает более старое значение, чем было прочитано ранее.
A=>1 | A=>0
Chaotic Write
Хаотичная запись — феномен переупорядочивания записей разных состояний, когда порядок их видимости не совпадает с порядком их выполнения.
1=>A | 1=>B |
| B=>1 | A=>0 | A=>1
Causal
Причинность — гарантия, что наблюдаемые операциями следствия идут строго после операций, послуживших их причинами.
Следующие феномены не допускаются, помимо тех, что запрещает монотонность:
Invisible Write
Невидимая запись — феномен ненаблюдаемого изменения, внесённого тем же агентом на том же узле.
1=>A | A=>0
Causeless Write
Беспричинная запись — феномен ненаблюдаемого изменения, на котором основано другое изменение.
A=>1 | A=>B |
| B=>1 | A=>0
Так как для поддержания причинности согласование с другими узлами не требуется, то эти и более слабые гарантии сохраняются и при разделении сети, но только если агент не переключается между узлами.
Sequential
Упорядоченность — гарантия единого порядка всех изменений, наблюдаемого всеми агентами.
Следующие феномены не допускаются помимо тех, что запрещает причинность:
Variable Order
Вариативное упорядочивание — феномен наблюдения изменений в разном порядке разными агентами.
A=>1 | B=>0 | B=>1
B=>1 | A=>0 | A=>1
Так как для гарантии единого порядка требуется координация между узлами, то эти и более сильные гарантии не могут быть обеспечены при разделении сети.
Linearizable
Линеаризуемость — гарантия соответствия порядка наблюдения изменений порядку внесения их в реальном времени.
Следующие феномены не допускаются помимо тех, что запрещает упорядоченность:
Stale Read
Устарелое чтение — феномен чтения устаревшей версии значения при чтении после внесения боле свежего изменения другим агентом.
1=>A | 2=>A |
| A=>1
Гарантии изоляции транзакций
Транзакция — последовательная группа операций с общим жизненным циклом. Операции из транзакции применяются либо все, либо ни одна и тогда говорят об откате транзакции.
Read Uncommitted
Видимость незакомиченного — гарантия атомарности записей транзакции. Операции записи разных транзакций не перемешиваются между собой, но при этом уже внесённые изменения непересекающихся состояний видимы между транзакциями.
Следующие феномены не допускаются:
Dirty Write
Грязная запись — феномен затирания изменения состояния другой транзакцией до завершения текущей, что приводит к частичной потере изменений.
[ 1=>A | | A=>2 ]
[ 2=>A ]
Read Committed
Видимость закомиченного — гарантия невидимости изменений ещё не завершённых транзакций.
Следующие феномены не допускаются помимо тех, что запрещает видимость незакомиченного:
Dirty Read
Грязное чтение — феномен видимости изменения, вносимого другой транзакцией, до её завершения. Таким образом откат транзакции может не откатить спровоцированные ею побочные эффекты.
{ 1=>A | } | [ A=>0 ]
[ A=>1 ]
Repeatable Read
Воспроизводимое чтение — гарантия неизменности видимых состояний в рамках транзакции, которая сама эти состояния не меняла.
Следующие феномены не допускаются помимо тех, что запрещает видимость закомиченного:
Phantom / Fuzzy Read
Нечёткое чтение — феномен получения разных значений при последовательном чтении одного и того же состояния.
Фантомное чтение — частный случай нечёткого чтения, касающийся чтения индекса одной транзакцией, в то время как другая меняет сами индексируемые записи.
[ A=>0 | | A=>1 ]
[ 1=>A ]
❗ Стандарт SQL опрометчиво не исключает феномен фантомного чтения из воспроизводимого чтения, что не корректно, так как фантомное чтение является проявлением нечёткого чтения таблицы или построенного по ней индекса.
Так как для поддержания воспроизводимости чтения согласование с другими узлами не требуется, то эти и более слабые гарантии могут быть сохранены даже при разделении сети. Вырожденный случай — изолированные client-side транзакции.
Serializable
Сериализуемость — гарантия видимости транзакций на любом узле, эквивалентно исполнению их последовательно на одном узле без перемешивания любых операций между транзакциями.
Следующие феномены не допускаются помимо тех, что запрещены воспроизводимым чтением:
Lost Update
Потерянное обновление — феномен затирания изменений одной транзакции изменениями другой, не учитывающей изменения первой.
[ A=>0 | 0+=>A ] | [ A=>1 ]
[ A=>0 | | 0+=>A ]
С такой гарантией транзакции могут сами рассматриваться как атомарные операции, удовлетворяющими гарантии упорядоченности, то есть имеющими глобальный порядок, а значит эти и более сильные гарантии не могут быть обеспечены при разделении сети.
Strict Serializable
Строгая сериализуемость — гарантия видимости сериализуемых транзакций в соответствии с их исполнением в реальном времени, то есть транзакции ведут себя как линеаризуемые атомарные операции.
Высокая доступность
Для обеспечения высокой доступности приходится отказываться от тотальной упорядоченности транзакций. А это значит, что нужно быть готовым к некоторыми феноменам.
Часть из них могут нивелированы путём использования CRDT структур, дающих одинаковый результат даже при перестановке операций местами. Но даже они не могут защитить от устарелого чтения. А значит всё равно приходится выбирать между доступностью и линеаризуемостью — эта дилемма так же известна как CAP-теорема.
Если допускать переключение агента между узлами, то хоть и можно обеспечить некоторый уровень изоляции транзакций, но временны́е аномалии всё равно неизбежны, что сводит всю пользу пользу от транзакций на нет. Поэтому разумным видится та или иная форма привязки агента к узлу и отказ от доступности в случае отказа этого узла.