- Обзор
- Пессимистический контроль параллелизма
- оптимистичный контроль параллелизма
- Многоверсионный контроль параллелизма
- Суммировать
- Reference
Изучив программирование в течение нескольких лет, вы обнаружите, что не существует простых и быстрых решений для всех проблем, а многие проблемы требуют компромиссов и компромиссов, и эта статья знакомит с компромиссами и сериализуемостью баз данных. механизм.
Если все транзакции в базе данных выполняются последовательно, это может легко стать узким местом производительности всего приложения.Хотя узлы, которые не могут масштабироваться горизонтально, в конце концов станут узким местом, база данных, которая выполняет транзакции последовательно, ускорит процесс. параллелизм делает возможным все, он может решить некоторые проблемы с производительностью, но он приведет к более странным ошибкам.
После введения параллельных транзакций, если вы не контролируете выполнение транзакций, возникнут различные проблемы.Вы можете не наслаждаться улучшением производительности, вызванным параллелизмом, и вас будут мучать различные странные проблемы.
Обзор
Как контролировать параллелизм — одна из самых важных проблем в области баз данных, но до сих пор было много зрелых решений для управления параллелизмом транзакций, и принципы этих решений — это то, что мы хотим представить в этой статье, которая будет представлена в article Три наиболее распространенных механизма управления параллелизмом:
Это пессимистичный контроль параллелизма, оптимистичный контроль параллелизма и многоверсионный контроль параллелизма, среди которых пессимистичный контроль параллелизма на самом деле является наиболее распространенным механизмом контроля параллелизма, то есть блокировками; а оптимистичный контроль параллелизма на самом деле имеет другое название: оптимистичные блокировки, оптимистичные блокировки на самом деле это не настоящая блокировка, мы подробно расскажем о ней в конце статьи; последняя — это многоверсионный контроль параллелизма (MVCC), используемый в сочетании для повышения производительности чтения базы данных.
Поскольку эта статья описывает различные механизмы контроля параллелизма, то он должен быть связан с различными параллельными транзакциями, как работают механизмы, мы проанализируем схематическим образом.
Пессимистический контроль параллелизма
Управление получением одних и тех же данных различными транзакциями является наиболее фундаментальным методом обеспечения согласованности базы данных.Если мы можем позволить транзакциям иметь исключительную возможность доступа к одному и тому же ресурсу в одно и то же время, мы можем гарантировать, что различные транзакции, работающие на одном ресурсе не будут взаимодействовать друг с другом.
Самый простой и наиболее широко используемый метод — использовать блокировки для решения проблемы.Когда транзакции необходимо оперировать ресурсом, ей необходимо сначала получить блокировку, соответствующую ресурсу, чтобы гарантировать, что другие транзакции не получат доступ к ресурсу, а затем выполнить различные операции над ресурсом; При пессимистическом управлении параллелизмом программа базы данных пессимистично относится к изменяемым данным и будет заблокирована во время обработки данных для решения проблемы конкуренции.
Блокировка чтения-записи
Чтобы максимизировать параллельные возможности транзакций базы данных, блокировки в базе данных разработаны в двух режимах: разделяемые блокировки и блокировки мьютекса. Когда транзакция получает общую блокировку, она может выполнять только операции чтения, поэтому общая блокировка также называется блокировкой чтения; и когда транзакция получает блокировку мьютекса для строки данных, она может читать и записывать строку данных. поэтому блокировки взаимного исключения также называются блокировками записи.
В дополнение к ограничению операций чтения и записи, которые могут выполнять транзакции, общие блокировки и блокировки мьютексов также имеют отношение «совместно используемое» и «взаимное исключение», то есть несколько транзакций могут одновременно получить общую блокировку строки данных, но Мьютексы несовместимы с разделяемыми блокировками и другими мьютексами, и мы, естественно, можем понять причину такой конструкции: несколько транзакций, записывающих одни и те же данные в одно и то же время, неизбежно вызовут различные странные проблемы.
Если текущая транзакция не может получить блокировку, соответствующую строке данных, она перейдет в состояние ожидания, пока другие транзакции не снимут блокировку, соответствующую текущим данным, блокировка может быть получена и соответствующая операция может быть выполнена. .
Протокол двухфазной блокировки
Протокол двухфазной блокировки (2PL) — это протокол, гарантирующий сериализуемость транзакций, который делит получение и снятие блокировок транзакции на две отдельные фазы: увеличение и сокращение.
На этапе роста транзакция может получать блокировки, но не может снимать блокировки, в то время как на этапе сокращения транзакции могут только снимать блокировки, но не могут приобретать новые блокировки.Если вы посмотрите только на определение 2PL, то оно было введено здесь, но у него все еще есть два варианта:
- Strict 2PL: транзакция проведенавзаимоисключающийБлокировка должна быть снята после фиксации;
- Rigorous 2PL: транзакция проведенавсеБлокировка должна быть снята после фиксации;
Хотя использование блокировок может решить проблемы, вызванные одновременным выполнением различных транзакций, использование двухэтапных блокировок создает еще одну серьезную проблему — взаимоблокировку; разные транзакции, ожидающие ресурсов, которые были заблокированы друг другом, вызывают взаимоблокировку. вот простой пример:
Две транзакции получают блокировки на ресурсах draven и beacon соответственно в начале, а затем возникает взаимоблокировка, когда они запрашивают блокировки, которые уже получены другой стороной.Ни одна из сторон не может ждать освобождения блокировок.Если нет механизм обработки взаимоблокировки, он будет ждать бесконечно долго, и ни одна транзакция не может быть завершена.
Обработка взаимоблокировок
Тупики часто встречаются в многопоточном программировании. Когда несколько потоков участвуют в борьбе за ресурсы, необходимо учитывать, не вызовут ли текущие потоки или транзакции взаимоблокировки. Вообще говоря, есть два способа решения взаимоблокировок. Один из них — предотвратить возникновение взаимоблокировок. и возникновение тупика из источника, а другой - позволить системе войти в состояние тупика, но когда в системе возникает тупик, его можно обнаружить и вовремя восстановить.
предотвращение взаимоблокировок
Есть два способа помочь нам предотвратить возникновение тупиковых ситуаций: один из них состоит в том, чтобы убедиться, что в ожидании между транзакциями нет петли, то есть граф ожидания между транзакциями должен бытьНаправленный ациклический граф, не существует циклических ожиданий или гарантий того, что все ресурсы, которые транзакция хочет получить, атомарно заблокированы в начале транзакции и что все ресурсы либо заблокированы, либо не заблокированы.
Однако у этого метода есть две проблемы: трудно определить, какие ресурсы необходимо заблокировать в начале транзакции, в то же время, поскольку некоторые данные, которые будут использоваться очень поздно, блокируются заранее, коэффициент использования данных и скорость параллелизма транзакций также очень высоки. Одним из решений является блокировка всех строк данных в определенном порядке и в то же время объединение с протоколом 2PL, чтобы гарантировать блокировку всех строк данных в порядке от меньшего к большему на этапе блокировки, но этот метод по-прежнему требует, чтобы транзакции знали заранее. времени, какие наборы данных будут заблокированы.
Другим способом предотвращения взаимоблокировки является использование вытеснения и отката транзакции для предотвращения взаимоблокировки.Когда транзакция начинает выполняться, сначала будет получена метка времени.Программа базы данных решит, должна ли транзакция ждать или откатиться в соответствии с меткой времени транзакции. В настоящее время у нас также есть два механизма на выбор, один из них — механизм ожидания:
Когда временная метка выполняющейся транзакции меньше, чем у другой транзакции, то есть транзакция A начинается раньше B, тогда она будет ждать, пока другая транзакция снимет блокировку с соответствующего ресурса, в противном случае она сохранит текущую временную метку и откатится.
Другой механизм называется ранним ожиданием, который представляет собой упреждающее решение, которое является полной противоположностью механизма ожидания.Если текущая транзакция выполняется до другой транзакции и запрашивает ресурсы другой транзакции, то другая транзакция будет свернута. обратно немедленно, отдавая ресурс транзакции, которая выполняется первой, в противном случае она будет ждать, пока другие транзакции освободит ресурс:
Оба метода приведут к ненужному откату транзакций, что приведет к определенной потере производительности.Более простой способ решить тупиковую ситуацию — использовать период тайм-аута, но настройку периода тайм-аута необходимо тщательно продумать, иначе это приведет к транзакциям, которые долгое время не может нормально выполняться, или взаимоблокировки, которые необходимо разрешить, не могут быть вовремя обнаружены, поэтому его использование все же имеет определенные ограничения.
Обнаружение взаимоблокировки и восстановление
Если программа базы данных не может гарантировать, что взаимоблокировка в принципе не произойдет посредством соглашения, то необходимо вовремя обнаружить взаимоблокировку и восстановить ее из состояния взаимоблокировки в нормальное состояние, чтобы программа базы данных могла нормально работать. При использовании метода обнаружения и восстановления для устранения взаимоблокировки программа базы данных должна поддерживать справочную информацию между данными и транзакцией, а также должна предоставить алгоритм для оценки того, вошла ли текущая база данных в состояние взаимоблокировки. возникает взаимоблокировка Обеспечьте соответствующие стратегии для своевременного восстановления.
В предыдущем разделе мы фактически упоминали, что об обнаружении взаимоблокировки можно судить по направленному графу ожидания.Если транзакция зависит от данных, обрабатываемых другой транзакцией, то текущая транзакция будет ожидать окончания другой транзакции. также является ребром во всем графе ожидания:
Как показано на рисунке выше, если в этом ориентированном графе появляется кольцо, это означает, что текущая база данных вошла в состояние взаимоблокировки.TransB -> TransE -> TransF -> TransD -> TransB
, в это время необходимо подключить механизм восстановления взаимоблокировки.
Как выйти из взаимоблокировки на самом деле очень просто. Наиболее распространенным решением является выбор транзакции во всем кольце для отката, чтобы разорвать цикл во всем графе ожидания.Во всем процессе восстановления необходимо учитывать три вещи:
Каждый раз, когда происходит взаимоблокировка, будут затронуты несколько транзакций, и необходимо выбрать, какую задачу откатить.Золотой принцип при выборе жертвы (Victim) заключается в следующем.минимизировать стоимость, поэтому нам необходимо всесторонне учитывать такие факторы, как время расчета транзакции, используемые строки данных и вовлеченные транзакции; когда мы выбираем жертву, мы можем начать откат. На самом деле есть два варианта отката. это откатить все, а другой — частичный откат.Частичный откат будет выполнен до контрольной точки перед транзакцией.Если контрольной точки нет, частичный откат выполнить невозможно.
Фактически, в процессе восстановления взаимоблокировки некоторые задачи могут быть выбраны как жертвы в нескольких взаимоблокировках, и они не будут успешно выполняться все время, что приведет к голоданию.Нам нужно обеспечить, чтобы транзакция была за конечное время. Выполняется в пределах области действия, поэтому при выборе жертвы учитывайте метку времени.
блокировка детализации
До сих пор мы не обсуждали различные блокировки детализации.Мы всегда обсуждали блокировки строк данных, но иногда мы хотим рассматривать несколько узлов как единицу данных и использовать блокировки для прямого подключения этой единицы данных, Таблицы и даже базы данных заблокированы. Реализация этой цели требует от нас определить в базе данных блокировки разной степени детализации:
Когда у нас есть блокировки разной степени детализации, если транзакция хочет заблокировать всю базу данных или всю таблицу, ей нужно просто заблокировать соответствующий узел, и к текущему узлу будет добавлена явная блокировка. узлов; хотя такого рода блокировки разной степени детализации могут решить проблему, заключающуюся в том, что дочерние узлы не могут быть заблокированы, когда родительский узел заблокирован, у нас нет возможности сразу определить родительский узел, когда дочерний узел заблокирован.
В этот момент нам необходимо представитьблокировка намеренияЧтобы решить эту проблему, когда вам нужно заблокировать дочерние узлы, сначала добавьте соответствующие блокировки намерения ко всем родительским узлам.Блокировки намерения вовсе не являются взаимоисключающими, а используются только для того, чтобы помочь родительскому узлу быстро определить, может ли он Узел заблокирован:
Вот изображение, которое представляет две блокировки намерения,Общая блокировка намеренияа такжемьютекс намеренияЗатем отношения совместимости между всеми блокировками; здесь мы ускорили пропускную способность базы данных с помощью различных блокировок детализации и блокировок намерения.
оптимистичный контроль параллелизма
Помимо пессимистического механизма контроля параллелизма — блокировок, у нас на самом деле есть и другие механизмы контроля параллелизма,оптимистичный контроль параллелизма(Оптимистический контроль параллелизма). Оптимистический контроль параллелизма также называют оптимистической блокировкой, но это не настоящая блокировка.Многие люди ошибочно думают, что оптимистическая блокировка — это настоящая блокировка, но это всего лишь идея контроля параллелизма.
В этом разделе мы сначала представимМеханизм управления параллелизмом на основе меток времени, а затем расширить на основе этого протокола для реализации механизма управления оптимистичным параллелизмом.
Протокол на основе метки времени
Протокол блокировки выполняется последовательно в соответствии со временем, запрошенным различными транзакциями для одного и того же элемента данных, потому что данные, которые хочет получить более поздняя транзакция, будут заблокированы предыдущей транзакцией и могут только ждать освобождения блокировки, поэтому протокол на основе блокировки выполняет порядок транзакций. Зависит от порядка, в котором устанавливаются блокировки. Протокол на основе временных меток, который я хочу здесь представить, способен определять порядок выполнения транзакций до их выполнения.
Каждая транзакция будет иметь глобально уникальную временную метку, которая может использовать либо системное время, либо счетчик, при условии, что все временные метки гарантированно уникальны и увеличиваются с течением времени.
Протокол на основе временных меток может гарантировать, что порядок параллельного выполнения транзакций будет точно таким же, как и эффект последовательного выполнения транзакций в соответствии с временными метками; каждый элемент данных имеет две временные метки, временную метку чтения и временную метку записи, соответственно представляющие текущее успешное выполнение. Отметка времени транзакции, соответствующая операции.
Этот протокол может гарантировать, что все конфликтующие операции чтения и записи могут выполняться последовательно в соответствии с размером временной метки.При выполнении соответствующей операции вам не нужно обращать внимание на другие транзакции, нужно только заботиться о значении временной метки. соответствующий элементу данных:
Независимо от того, является ли это операцией чтения или записи, значение временных меток чтения и записи будет сравниваться слева направо. Если оно меньше текущего значения, оно будет отклонено и выполнено откат. Система базы данных добавит новую временную метку для отмененной транзакции и перезапустить ее. Выполнить эту транзакцию.
Протокол на основе аутентификации
оптимистичный контроль параллелизмаПо сути, это протокол, основанный на верификации, поскольку в большинстве приложений транзакции только для чтения составляют подавляющее большинство, а возможность конфликта между транзакциями из-за операций записи очень мала, а это значит, что для большинства транзакций не требуется Механизм управления параллелизмом также может работать очень хорошо и также может обеспечивать согласованность базы данных, а механизм управления параллелизмом на самом деле добавляет много накладных расходов всей системе баз данных, и мы можем уменьшить эти накладные расходы с помощью других стратегий.
Протокол верификации — это найденное нами решение, которое делит выполнение всех транзакций на два-три этапа в зависимости от того, транзакция доступна только для чтения или обновляется:
На этапе чтения база данных выполняетВсе операции чтения и записи, и хранить все записанные значения во временных переменных, то реально не обновит содержимое базы данных, в это время она перейдет на следующий этап, программа базы данных проверит законны ли текущие изменения, т.е. есть ли другие транзакции в Данные обновляются во время ЭТАПА RAED. Если они проходят тест, они напрямую переходят на ЭТАП ЗАПИСИ, чтобы записать все изменения во временных переменных в базу данных. Транзакции, которые не проходят тест, будут прекращается напрямую.
Чтобы обеспечить нормальную работу оптимистического управления параллелизмом, нам необходимо знать время возникновения различных фаз транзакции, включая время начала транзакции, время начала фазы проверки и время окончания фазы записи; через Эти три временные метки, мы можем гарантировать, что любые конфликтующие транзакции не будут записаны в базу данных в то же время.Как только транзакция завершит этап проверки, она будет записана немедленно, а другие транзакции, которые считывают те же данные, будут отброшены и повторно казнен.
Будучи оптимистичным механизмом управления параллелизмом, он предполагает, что все транзакции в конечном итоге пройдут фазу проверки и будут успешно выполнены, в то время как механизмы блокировки и протоколы на основе меток времени пессимистичны, поскольку заставляют транзакции ждать или возвращаться в случае конфликта. если нет необходимости в блокировках, можно обеспечить отсутствие конфликта между транзакциями.
Многоверсионный контроль параллелизма
Механизмы управления параллелизмом, которые мы представили до сих пор, на самом деле предназначены для разрешения условий гонки между транзакциями путем задержки или завершения соответствующих транзакций для обеспечения сериализуемости транзакций; хотя предыдущие два механизма управления параллелизмом действительно могут принципиально решить проблему сериализуемости параллельных транзакций. но в реальной среде транзакции базы данных в основном доступны только для чтения, а запрос на чтение во много раз превышает запрос на запись.Если перед запросом на запись и запросом на чтение нет механизма управления параллелизмом, то в худшем случае запрос на чтение считывает уже записанные данные, что вполне приемлемо для многих приложений.
В соответствии с этой основной предпосылкой система базы данных представляет еще один механизм управления параллелизмом —Многоверсионный контроль параллелизма(Multiversion Concurrency Control), каждая операция записи будет создавать новую версию данных, а операция чтения будет выбирать наиболее подходящий результат из ограниченного числа версий данных и возвращать его напрямую; в это время конфликт между операциями чтения и операции записи станут уже не требующими внимания, а управление и быстрая подборка версий данных становится основной проблемой, которую необходимо решить MVCC.
MVCC не является антитезой оптимистического и пессимистического управления параллелизмом, его можно хорошо комбинировать с ними для увеличения параллелизма транзакций.MVCC реализован в самых популярных базах данных SQL MySQL и PostgreSQL, но из-за того, что они реализуют пессимистическую блокировку и оптимистическую блокировку соответственно, поэтому способ реализации MVCC тоже отличается.
MySQL и MVCC
Многоверсионный протокол двухфазной блокировки (Multiversion 2PL), реализованный в MySQL, сочетает в себе преимущества MVCC и 2PL.Каждая версия строки данных имеет уникальную временную метку.При запросе на чтение транзакции программа базы данных будет непосредственно из Возвращает самую большую отметку времени среди нескольких версий элемента данных.
Операция обновления немного сложнее.Транзакция сначала прочитает последнюю версию данных, чтобы вычислить результат обновления данных, а затем создаст новую версию данных.Временная метка новых данных является самой большой версией текущая строка данных.+1
:
Удаление версии данных также выбирается в соответствии с отметкой времени.MySQL будет периодически удалять данные с самой низкой версией из базы данных, чтобы гарантировать отсутствие большого количества устаревшего контента.
PostgreSQL и MVCC
В отличие от использования пессимистического контроля параллелизма в MySQL, в PostgreSQL используется оптимистический контроль параллелизма, что приводит к некоторым отличиям в реализации MVCC в комбинации оптимистичных блокировок.Окончательная реализация называется Multiversion Timestamp Sorting Protocol. Ordering), в этом протоколе всем транзакциям присваивается уникальная временная метка перед выполнением, и каждый элемент данных имеет две временные метки для чтения и записи:
Когда транзакция PostgreSQL отправляет запрос на чтение, база данных напрямую возвращает последнюю версию данных, не блокируясь какой-либо операцией.При выполнении операции записи отметка времени транзакции должна быть больше или равна отметке времени чтения строки данных. , иначе произойдет откат.
Реализация этого MVCC гарантирует, что транзакция чтения никогда не завершится ошибкой и не нужно ждать освобождения блокировки.Для приложений с гораздо большим количеством запросов на чтение, чем запросов на запись, оптимистическая блокировка плюс MVCC может значительно повысить производительность базы данных; хотя этот протокол может обеспечить некоторые очевидные улучшения производительности в некоторых практических ситуациях, он также приводит к двум проблемам: во-первых, каждая операция чтения будет обновлять метку времени чтения, что приводит к двум операциям записи на диск, а во-вторых, между транзакциями. путем отката, поэтому, если вероятность конфликта очень высока или откат обходится дорого, производительность чтения и записи базы данных будет не такой хорошей, как при использовании традиционного метода ожидания блокировки.
Суммировать
Механизм управления параллелизмом базы данных сегодня имеет очень зрелое и полное решение Нам не нужно разрабатывать новый протокол для разрешения конфликта между различными транзакциями Что мы узнали из механизма управления параллелизмом базы данных Соответствующие знания, будь то блокировки или оптимистичный контроль параллелизма широко используются в других областях или приложениях, поэтому необходимо понимать и быть знакомым с принципами различных механизмов контроля параллелизма.
Оригинальная ссылка:Говоря об управлении параллелизмом базы данных — блокировка и MVCC · Программирование, ориентированное на веру
Follow: Draveness · GitHub