Понимание Google Spanner (3): принцип и реализация распределенных транзакций

база данных

В этой статье рассказывается о принципе распределенных транзакций и реализации транзакций Spanner. Вам необходимо иметь общее представление о транзакциях с базой данных на одной машине. Если вы еще этого не понимаете, вы можете посмотреть две предыдущие статьи:

Чтобы сделать следующее чтение менее скучным, давайте зададим вам несколько вопросов для размышления:

  1. Каковы трудности распределенных транзакций по сравнению с автономными транзакциями? Как решить?
  2. Почему в той же транзакции Spanner вообще не может читать свои собственные записи, пока она не зафиксируется?
  3. Что такое внешняя согласованность?
  4. Какие существуют типы транзакций Spanner? К каким сценариям они применимы?
  5. Чтение Spanner заблокировано или MVCC?
  6. Есть ли ограничение на пропускную способность транзакций Spanner в секунду для каждой группы Paxos?

Во-первых, принцип распределенных транзакций

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

1. Проблемы, с которыми сталкиваются распределенные транзакции

В ACID транзакций для автономной базы данных A (атомарность) и C (непротиворечивость) легко выполняются, A основано на журнале отмен и C на основе журнала повторов и блокировки, но для распределенной базы данных это относительно Сложность возникает не только из-за увеличения сложности от одной машины к нескольким машинам, но и из-за нестабильного фактора «сети» посередине.

Задача 1: Атомарность

Транзакции должны удовлетворять требованиям A: либо все завершатся неудачно, либо все завершатся успешно.Для одномашинной базы данных, пока транзакция записывается в журнал, можно гарантировать, что транзакцию можно будет отменить или зафиксировать.Распределенные транзакции являются множественными. машина сделки.. отличается,有的机器可能写日志成功,有的机器可能写日志失败(比如因为获取锁失败),也就是会出现部分成功部分失败的情况,因此分布式数据库该如何保证原子性,是一个挑战.

Задача 2: Порядок транзакции

Транзакция, которая начинается позже, должна иметь возможность считывать записи транзакции, которая завершилась до ее начала.Для правильного MVCC транзакция должна иметь монотонно возрастающую отметку времени или порядковый номер транзакции для обеспечения логического порядка.

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

Задача 3: нестабильная сеть

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

2. Идеи решений для распределенных транзакций

Второй этап фиксации (2PC)

для вышеперечисленногоатомарностьа такженестабильная сетьДля этих двух задач более общими решениями для распределенных транзакций являются:Двухфазная фиксация (Tow-Phase Commit), сокращенно 2PC, Spanner и TiDB используют двухэтапную фиксацию,它将提交分为准备和最终提交两个阶段, обратите внимание на разницу между "окончательной фиксацией" и "фиксацией", упомянутой здесь. Во избежание путаницы, "фиксация" по-прежнему является исходной семантикой, представляющей фиксацию, выданную клиентом, а "окончательная фиксация" относится к фиксации фаза в 2PC, которая инициируется БД, а не клиентом.

Распределенные транзакции часто означают, что задействованы две или более БД, и в 2PC будут разные роли, среди которых有一台机器是协调者(Coordinator),可以理解为Team Leader,其余的都是参与者(Participant).

Этап 1: Подготовка

Когда клиент инициирует отправку, он начинает входить в первый этап 2PC - подготовка, также называемая голосованием (Vote), координатор уведомляет участников о начале подготовки, и каждый участник выполняет транзакцию локально. только приобретать блокировки и записывать журналы, а не применять эти изменения (мутации).Участники несут ответственность за подтверждение того, были ли их собственные записи успешными.Если это так, они должны вернуть координатору да.Если машина успешно выполняет транзакцию, она возвращает нет.

准备(投票)阶段

После того, как координатор выдаст инструкцию подготовки, он решит, следует ли зафиксировать (commit) или прервать (abort) в зависимости от ситуации участников.Есть два фактора, которые определяют окончательный выбор:

  1. Период ожидания
  2. Ответы участников

Что касается периода ожидания, то из-за неопределенности сети инструкции, выданные координатором, могут быть получены не каждым участником, или ответы, выданные участниками, могут быть не получены координатором, и эта нестабильность существует все время. Нет уверенности в том, что клиент сможет получить ответ в течение приемлемого для клиента времени, а доступность (A в CAP) не будет удовлетворена, если время превысит допустимое время клиента, поэтому координатор не может ждать все время , и необходимо установить период ожидания.Если не получен ответ от всех участников, то напрямую считается, что не ответивший участник говорит нет вместо да, и координатор напрямую принимает решение о прекращении.

По второму пункту - ответ участника, если координатор успешно получает ответы от всех участников в течение периода ожидания, он начинает следующее суждение, если все говорят да, то есть ответ "можно отправить", и координатор будет Если он также находится в состоянии отправки, будет принято решение о фиксации.Если какой-либо участник возвращает, что он не может быть отправлен, или координатор не может представить себя, то координатор примет решение об отмене.

Второй этап: окончательный коммит (final commit)

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

Для участника, когда он ответил «да» или «нет» на первый этап, он перешел на второй этап, ожидая решения координатора и выполняя решение. На этом этапе координатор может активно отправлять решение участникам, либо участники могут активно опрашивать.2PC — алгоритм с разными реализациями.

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

Почему участникам разрешено отправлять асинхронно?

Очень просто, потому что каждый участник успешно выполнил транзакцию и записал в лог.Раз лог размещен на диске, значит транзакция гарантированно 100% успешна.Тогда решение координатора сводится только к формальной подаче заявки изменения транзакции и снять блокировку.И блокировка, и применение могут быть асинхронными, что не влияет на гарантию того, что транзакция может быть «успешной», поэтому ее можно безопасно вернуть клиенту.

Основная идея 2PC заключается в том, чтобы убедиться, что каждый может добиться успеха, прежде чем принимать решение о подаче, и, если у кого-то из участников может не получиться, принять решение о приостановке.

2. Реализация гаечной транзакции

Модель транзакций Spanner является реализацией 2PC, поэтому вы должны иметь определенное представление о 2PC, прежде чем читать ее.

1. Внешняя согласованность

Давайте сначала посмотрим на Спаннера издалека и вблизи, от исполнения Спаннера до реализации Спаннера. **Внешняя согласованность** — это концепция, предложенная Google. Упомянутый здесь внешний можно понимать как клиент, то есть для клиента порядок двух наблюдаемых им транзакций должен быть таким же, как и порядок их фиксации. , поэтому, если транзакция 1 фиксируется до транзакции 2, то транзакция 2 должна иметь возможность прочитать изменения транзакции 1. Как показано ниже:

外部一致性

Хотя транзакция 2 начинается до фиксации транзакции 1, ее фиксация происходит позже, и она должна быть в состоянии прочитать изменения транзакции 1.

Внешняя согласованность основана только на конечном результате модели транзакции Spanner, это производительность, а не причина, поэтому здесь нам нужно знать только окончательную производительность транзакции Spanner, чтобы позволить всем думать о проблемах сверху вниз. вниз Как добиться этого эффекта.

2. TrueTime

Распределенные транзакции должны решить три проблемы, упомянутые выше. Здесь давайте поговорим о проблеме 2 — порядке транзакций. Как обеспечить, чтобы порядковый номер транзакции увеличивался распределенным способом? Легко думать об авторизации одной точки для назначения последовательности транзакций. номера. , каждая транзакция получает свой порядковый номер из этой единственной точки. В модели транзакций Google Percolator существует глобальный сервер синхронизации (TSO), и все транзакции получают метку времени от TSO в качестве своего порядкового номера, поэтому он должен быть монотонным. Инкрементальный, конечно, чтобы обеспечить доступность, сама эта единая точка тоже может быть кластером.Например, TiDB использует кластер PD в качестве TSO.

Но Спаннер не использует путь глобального передатчика номера, потому что у него есть черная технология - TrueTime, которая реализована аппаратно, в каждом дата-центре есть несколько мастеров времени, большинство мастеров оснащены GPS, а остальные несколько мастеров являются оснащены атомными часами. Благодаря определенным алгоритмам и калибровке их время почти совпадает с реальным абсолютным временем. Все БД будут отправляться на эти серверы для калибровки своего времени каждые 30 секунд, чтобы гарантировать, что их время также совпадает с реальным абсолютным временем. Почти то же самое, что гарантирует, что ошибка между временем каждого сервера БД и реальным абсолютным временем находится в пределах нескольких миллисекунд, в то время как ошибка традиционной калибровки NTP составляет сотни миллисекунд, поэтому TrueTime гарантирует, что сервер БД практически близко к точному времени, поэтому вообще нет необходимости в глобальном эмитенте, так как на каждом сервере время почти одинаковое.

TrueTime — это набор API-интерфейсов, и вызов TT.now() вернет значение [earliest, last], указывающее, когда реальное абсолютное время является самым ранним и самым поздним, и время должно попадать в этот интервал.

TrueTime

3. Классификация сделок

Spanner делит транзакции на две категории: транзакция чтения-записи и транзакция только чтения.

Транзакции только для чтения подразделяются на

  • Моментальная транзакция (сильное чтение)
  • Чтение временной метки, выбранное клиентом (клиент указывает временную метку с истекшим сроком действия для чтения)
  • Выбранное клиентом связанное чтение (клиент указывает самую раннюю отметку времени, которая не может быть превышена для чтения)

Транзакции только для чтения — это все транзакции на основе снэпшотов, и все они не блокируются.

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

事务类型与实现

3. Чтение записи транзакции

Spanner не использует 2PC для всех транзакций. Для транзакций с одним разделением он может быть переведен в отдельную транзакцию. Использование 1PC является оптимизацией эффективности. Поэтому для транзакций с одним и несколькими разделениями Spanner использует 1PC и 2PC соответственно. Ниже мы обсудим отдельно.

Единая разделенная транзакция (1PC)

Разницы между 1ПК и 2ПК по сути нет, и подача разбита на два шага (здесь не два пункта, а только два шага, чтобы отличить их от двухэтапной подачи), первый шаг - получение локов, запись журнала, второй шаг - применить изменения и снять блокировки. Единственное отличие состоит в том, что 2PC имеет сложный процесс принятия решений и уведомлений между первым и вторым шагами. Необходимо убедиться, что все сплиты реагируют одинаково: отправить или отменить. А в 1ПК как раз не хватает сложного процесса принятия решения и уведомления посередине, а в других почти нет разницы.

Для Single Split Transaction она на самом деле очень похожа на транзакцию общей автономной базы данных, но есть очевидное отличие, то есть в модели транзакций Spanner каждый раз, когда Write не выполняется на стороне клиентского API, SQL отправляется на сервер БД, но все кэшируется локально, что полностью отличается от автономных баз данных, таких как MySQL.Для MySQL каждый раз, когда выполняется запись SQL, он будет немедленно отправлен на сервер и попытается блокировать и записывать журналы, в то время как клиент Spanner будет кэшироваться локально Все записи отправляются в Spanner сразу только тогда, когда клиент вызывает метод фиксации.由于这种缓存机制,在事务被commit前,都不能读到它自己的任何Writes.

Writes将被缓存,在client commit时发送给Spanner

Взгляните на процесс Spanner 1PC:

  1. Клиент считывает данные и немедленно отправляет запрос на чтение в Spanner.
  2. Spanner получает запрос на чтение и добавляет блокировку чтения к данным. Если он обнаружит, что данные заблокированы блокировкой записи, они не могут быть заблокированы немедленно. Ему необходимо дождаться фиксации транзакции с блокировкой записи, прежде чем продолжить закрой.
  3. Клиент записывает данные и в это время записывает только в локальный буфер
  4. Клиент завершает чтение и запись, то есть при вызове коммита в SDK клиент отправит все записи в буфере в Spanner
  5. Spanner начинает получать блокировку записи и запись в журнал
  6. После получения блокировки записи и записи журнала снова проверьте, существует ли еще блокировка чтения (поскольку она могла быть прервана механизмом ожидания остановки), если нет, транзакция должна быть прервана.
  7. Первичная реплика (ведущая реплика) использует TrueTime для создания метки времени для этой транзакции в качестве метки времени фиксации.
  8. Реплика лидера (транзакции чтения и записи могут происходить только в лидере) реплицирует журнал на другие реплики, и одновременно выполняет ожидание фиксации, т.к. консистентность, то есть после отправки Для всех серверов эта транзакция находится в прошедшем времени до того, как ее можно будет отправить.Фактические накладные расходы на ожидание фиксации невелики, т. к. репликация журнала также выполняется одновременно как commit-wait, а время простоя очень мало.После того, как реплики успешно реплицируются и commit-wait заканчивается, он может вернуть клиенту, что транзакция была успешно зафиксирована, и в то же время применить транзакцию к конечный автомат и снять блокировку.

Рана-подожди

Гаечный ключ невозможно заблокировать благодаря механизму ожидания с защитой от травм.

В процессе получения блокировки вы можете столкнуться с тем, что некоторые записи были заблокированы.Если блокировка записи удерживается, вам нужно дождаться фиксации или отмены транзакции, удерживающей блокировку.Если блокировка чтения удерживается, используйте рана-подожди,首先Spanner会进行死锁检测,如果这里不存在死锁,那么事务等待这个读锁释放,如果存在死锁,那么判断目前持有读锁的事务是比自己年轻还是年老,如果比自己年轻,则直接abort这个读锁,如果比自己年老,则需要等待年老事务主动释放锁. Травмированное ожидание полностью избегает взаимоблокировок, а также избегает голодания.

Множественная разделенная транзакция (2PC)

Множественная разделенная транзакция использует 2PC, но она не сильно отличается от 1PC, в основном потому, что транзакция одной группы Paxos становится транзакцией группы Paxos Group, и необходимо добавить координатора, и будут добавлены следующие шаги:

  1. Клиент будет нести ответственность за инициирование 2PC.При отправке записей в Spanner клиент сначала узнает, на какие серверы он должен отправлять записи, соответственно, и клиент выберет одну из этих ведущих реплик в качестве координатора. (чтение и запись транзакций. Это может произойти только с Лидером, поэтому другие реплики здесь не обсуждаются).
  2. После того, как каждый участник успешно получит все блокировки записи, будет сгенерирована метка времени подготовки, а затем журнал (который содержит блокировку) будет скопирован на большинство реплик через Paxos, а затем метка времени подготовки будет отправлена ​​координатору, указывая, что он все в порядке
  3. После того, как координатор получит метки времени подготовки всех участников, он сгенерирует метку времени фиксации, которая должна быть больше, чем все метки времени подготовки, и больше, чем TT.now().latest
  4. Координатор отправит команду участника после окончания ожидания фиксации.

ограничения фиксации-ожидания

Потому что при выборе отметки времени фиксации S необходимо убедиться, что S больше, чем TT.now().latest, а затем реальное время фиксации должно быть больше, чем S.latest.Если ошибка TrueTime равна ε, ожидание здесь выполняется 2ε, а средняя ошибка TrueTime составляет 4 мс,因此一个Paxos Group每秒吞吐量是 1000 / 2*4 = 125 事务/s,TrueTime误差越小,吞吐量越高.

Это тоже наводит на мысль.Так как пропускная способность ограничена коммитом-ожиданием, если неподходящий дизайн таблицы приводит к хотспотам, то большое количество транзакций чтения и записи будет достигать одного и того же Split, в результате чего будет низкая пропускная способность в секунду.对于较多读写事务的表,应该特别注意避免热点.

4. Транзакция только для чтения

Транзакции только для чтения основаны на временных метках, то есть на основе MVCC, поэтому все они не блокируются.Сильное чтение не требует от клиента предоставления временной метки, поэтому Spanner необходимо сначала получить последнюю текущую информацию от лидера реплики. Затем метка времени данных считывается на любой реплике. В дополнение к сильному чтению, другие могут называться устаревшим чтением (Stale Read).Клиент указывает временную метку для чтения или самую раннюю временную метку, которую можно допустить.Поэтому нет необходимости проходить Лидер, чтобы получить временную метку сначала , и его можно использовать в любой реплике.

Однако для трех вышеуказанных типов чтения перед завершением чтения реплика сначала проверит, достаточно ли у нее новых данных для выполнения чтения, и если нет, то синхронизируется с Лидером.

并不是整个事务周期中只有读取就算是只读事务,而是需要client事先声明开启的这个事务是只读的,否则会被当做读写事务执行。Исключением является выполнение одного чтения, которое явно не помещено в транзакцию, не требует явного объявления и также рассматривается как транзакция только для чтения.

5. Слепое письмо

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

兼容矩阵

Так как у Спаннера меньше общедоступной информации и он ограничен своим уровнем знаний, в тексте могут быть неточности Добро пожаловать на обмен.

использованная литература