Оптимистическая и пессимистическая блокировка

572

Я понимаю разницу между оптимистической и пессимистической блокировкой. Может ли кто-нибудь объяснить мне, когда я буду использовать один из них вообще?

И меняется ли ответ на этот вопрос в зависимости от того, использую ли я хранимую процедуру для выполнения запроса?

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

Джейсон Бейкер
источник
1
blog.couchbase.com/…
Фрэнк Мят Чт
1
Это хороший вопрос, особенно потому, что я читал о сериализуемостиAt any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts .
Маленький Чужой
1
Здесь вы можете найти хорошее объяснение, здесь, на SO, о том, что является корневой концепцией Оптимистической блокировки .
Диего

Ответы:

812

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

Если запись грязная (т. Е. Версия отличается от вашей), вы прерываете транзакцию, и пользователь может перезапустить ее.

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

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

В последнем случае вы открываете транзакцию с TxID, а затем повторно подключаетесь с использованием этого идентификатора. СУБД поддерживает блокировки и позволяет вам забрать сеанс обратно через TxID. Именно так работают распределенные транзакции, использующие протоколы двухфазной фиксации (такие как транзакции XA или COM + ).

ConcernedOfTunbridgeWells
источник
148
Оптимистическая блокировка не обязательно использует номер версии. Другие стратегии включают использование (a) метки времени или (b) всего состояния самой строки. Последняя стратегия уродлива, но позволяет избежать необходимости в выделенном столбце версий, если вы не можете изменить схему.
Эндрю Свон
2
@geek - протоколы распределенных транзакций, такие как XA, позволяют привязывать отдельный идентификатор транзакции к одной или нескольким системам. Этот тип протокола позволяет использовать блокировки через пул соединений, так как идентификатор транзакции отсоединяется от сеансов и предоставляется явно. Однако это приводит к определенным накладным расходам и может привести к утечкам блокировок и идентификаторов транзакций, если ваше приложение не заботится об их отслеживании. Это гораздо более тяжелое решение.
ConcernedOfTunbridgeWells
22
@supercat - не согласны с тем, что оптимистическая блокировка менее чем на 100% точна - поскольку она проверяет все входные записи для транзакции, которая должна оставаться неизменной в течение продолжительности, она так же точна, как и пессимистическая блокировка (выберите для стиля обновления) для этих те же записи. Основное отличие состоит в том, что оптимистическая блокировка приводит к накладным расходам только в случае конфликта, тогда как пессимистическая блокировка снижает накладные расходы при конфликте. Такой оптимизм лучше всего подходит в случае, когда большинство транзакций не конфликтуют - что, как я надеюсь, обычно имеет место для большинства приложений.
RichVel
2
@Legends - Оптимальная блокировка, безусловно, будет подходящей стратегией для веб-приложения.
ConcernedOfTunbridgeWells
2
Следует отметить, что выбор зависит также от соотношения чтения и записи: если ваше приложение в основном является приложением только для чтения большим количеством пользователей, а иногда вы записываете данные, используйте оптимистическую блокировку. Например, в StackOverflow много людей читают страницы, а иногда кто-то редактирует одну: в пессимистической блокировке кто получит блокировку? первый? В оптимистической блокировке человек, который хочет редактировать страницу, может сделать это, пока у него есть последняя версия.
Джехон
177

Оптимистическая блокировка используется, когда вы не ожидаете много столкновений. Обычная операция обходится дешевле, но если коллизия ДЕЙСТВИТЕЛЬНО произойдет, вы заплатите более высокую цену за ее разрешение при отмене транзакции.

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

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

Илья Кочетов
источник
В нормальном случае утверждение является идеальным, но в особых случаях, когда вы можете управлять операцией CAS, допуская неточность, как упомянуто в ответе @skaffman, я бы сказал, что это действительно зависит.
Слушай
75

Оптимистический предполагает, что ничего не изменится, пока вы читаете это.

Пессимистично предполагает, что что-то будет, и поэтому блокирует это.

Если не важно, что данные идеально читаются, используйте оптимизм. Вы можете получить странное «грязное» прочтение, но оно гораздо менее вероятно приведет к тупикам и тому подобному.

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

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

Да, и сервер Microsoft SQL по умолчанию блокирует страницу - в основном, строку, которую вы читаете, и несколько по обе стороны. Блокировка строк более точна, но намного медленнее. Часто стоит установить транзакции на фиксацию или отсутствие блокировки, чтобы избежать тупиков при чтении.

Кит
источник
JPA Optimistic Locking позволяет гарантировать постоянство чтения.
Гили
4
Непротиворечивость чтения является отдельной задачей - с PostgreSQL, Oracle и многими другими базами данных вы получаете согласованное представление данных независимо от того, какие обновления еще не зафиксированы, и на них не влияют даже исключительные блокировки строк.
RichVel
Я должен согласиться с @RichVel. С одной стороны, я вижу, как пессимистическая блокировка может предотвратить грязное чтение, если уровень изоляции вашей транзакции READ UNCOMMITTED. Но вводить в заблуждение утверждение о том, что оптимистическая блокировка подвержена грязному чтению, не следует упоминать, что большинство баз данных (включая, по-видимому, MS SQL Server) имеют уровень изоляции по умолчанию «READ COMMITTED», который предотвращает грязное чтение и делает оптимистическую блокировку такой же точной, пессимистично.
Антином
Эрик Брауэр говорит, что банкиры, в отличие от других, предпочитают грязные операции. Твои гуру кажутся совершенно безумными.
Маленький Чужой
1
Эрик Брюер - гуру, который дал теорему CAP, говорит о последовательности в банковском деле . Это противоположно тому, за что ты это чтишь.
Маленький инопланетянин
50

В дополнение к тому, что уже было сказано:

  • Следует сказать, что optimisticблокировка имеет тенденцию улучшать параллелизм за счет предсказуемости.
  • PessimisticБлокировка имеет тенденцию уменьшать параллелизм, но более предсказуема. Вы платите свои деньги и т.д ...
skaffman
источник
3
Я не вижу, как предсказуемость (как бы вы ее ни определяли) улучшается с помощью пессимистической блокировки - если вы имеете в виду «транзакция может завершиться после снятия блокировок», вы правы, но до тех пор, пока транзакция не получит все необходимые блокировки, она может столкнуться с задержкой для оставшиеся блокировки и фактически могут быть прерваны из-за логики обнаружения взаимоблокировок и разрешения БД. Приложения, использующие пессимистическую блокировку, могут иметь крайне непредсказуемое время выполнения - классический пример - когда кто-то блокирует запись X, затем идет на обед, затем пользователь блокирует записи X и Y, затем другие Y и Z и так далее, пока большинство пользователей не будут заблокированы. ..
RichVel
40

При работе с конфликтами у вас есть два варианта:

  • Вы можете попытаться избежать конфликта, и именно это делает пессимистическая блокировка.
  • Или вы могли бы допустить возникновение конфликта, но вам необходимо его обнаружить при совершении транзакций, и именно это делает Optimistic Locking.

Теперь давайте рассмотрим следующую аномалию Lost Update :

Потерянное обновление

Аномалия Lost Update может возникнуть на уровне изоляции Read Committed .

На диаграмме выше мы видим, что Алиса считает, что она может снять с нее 40, accountно не понимает, что Боб только что изменил остаток на счете, и теперь на этом счете осталось только 20.

Пессимистическая блокировка

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

Потерянное обновление Пессимистическая блокировка

На приведенной выше диаграмме Алиса и Боб получат блокировку чтения accountстроки таблицы, которую оба пользователя прочитали. База данных получает эти блокировки на SQL Server при использовании Repeatable Read или Serializable.

Поскольку Алиса и Боб прочитали значение accountсо значением PK 1, ни один из них не может изменить его, пока один пользователь не снимет блокировку чтения. Это связано с тем, что операция записи требует получения блокировки записи / эксклюзивной блокировки, а блокировки совместного использования / чтения предотвращают блокировку записи / эксклюзивной блокировки.

Только после того, как Алиса зафиксировала свою транзакцию и сняла блокировку чтения в accountстроке, Боб UPDATEвозобновит и применит изменения. Пока Алиса не снимет блокировку чтения, Боб UPDATE блокирует.

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

Оптимистическая блокировка

Оптимистическая блокировка позволяет конфликту возникать, но обнаруживает его после применения ОБНОВЛЕНИЯ Алисы по мере изменения версии.

Транзакции уровня приложения

На этот раз у нас есть дополнительный versionстолбец. versionСтолбца увеличивается каждый раз , когда UPDATE или DELETE выполняется, и он также используется в предложении WHERE в UPDATE и DELETE заявления. Чтобы это работало, нам нужно выполнить SELECT и прочитать текущее значение versionперед выполнением UPDATE или DELETE, так как в противном случае мы не знали бы, какое значение версии передать в предложение WHERE или увеличить.

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

Транзакции уровня приложения

Системы реляционных баз данных появились в конце 70-х начале 80-х годов, когда клиент, как правило, подключался к мэйнфрейму через терминал. Вот почему мы до сих пор видим, что системы баз данных определяют такие термины, как настройка SESSION.

В настоящее время через Интернет мы больше не выполняем операции чтения и записи в контексте одной и той же транзакции базы данных, и ACID больше не достаточно.

Например, рассмотрим следующий вариант использования:

введите описание изображения здесь

Без оптимистической блокировки это потерянное обновление невозможно было бы перехватить, даже если бы транзакции базы данных использовали Serializable. Это связано с тем, что чтение и запись выполняются в отдельных HTTP-запросах, следовательно, в разных транзакциях базы данных.

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

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

Вывод

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

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

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

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

Влад Михалча
источник
Для каких сценариев вы бы предложили выбрать OptimisticLocking и PessimisticLocking? Зависит ли это от того, как часто возникает исключение OptimisticLockException?
Кот Стимпсона
1
Это зависит от варианта использования. Иногда оптимистическая блокировка является единственным решением (например, транзакции с несколькими запросами). В других случаях пессимистическая блокировка является единственным решением (например, консультативные блокировки PostgreSQL ). Иногда их нужно комбинировать, как в случае с PESSIMISTIC_FORCE_INCREMENT.
Влад Михалча
22

Я бы подумал еще об одном случае, когда пессимистическая блокировка была бы лучшим выбором.

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

Николай
источник
Люди, пытающиеся использовать оптимистическую и пессимистичную блокировку, также могут встать, так сказать, на ноги друг друга. Представьте себе сценарий, когда оптимистический сеанс читает запись и выполняет некоторые вычисления, в то время как пессимистический сеанс обновляет запись, затем оптимистический сеанс возвращается и обновляет эту же запись, не замечая внесенных изменений. Выберите ... для обновления работает, только если каждый сеанс использует тот же синтаксис.
Lusional
Хорошее объяснение, отдам свой голос от меня
Дулай Кулатхунга
15

Есть в основном два самых популярных ответа. Первый один в основном говорит ,

Для Optimistic требуется трехуровневая архитектура, в которой вы не обязательно поддерживаете соединение с базой данных для своего сеанса, тогда как Pessimistic Locking - это когда вы блокируете запись для своего эксклюзивного использования до тех пор, пока не закончите с ней. У него гораздо лучшая целостность, чем у оптимистической блокировки, вам нужно либо прямое подключение к базе данных.

Другой ответ

Оптимистическое (управление версиями) быстрее из-за отсутствия блокировок, но (пессимистическое) блокирование работает лучше, когда конкуренция высока, и лучше предотвращать работу, чем отбрасывать ее и начинать заново.

или

Оптимистическая блокировка работает лучше всего при редких столкновениях

Как это написано на этой странице.

Я создал свой ответ, чтобы объяснить, как «сохранить соединение» связано с «низкими коллизиями».

Чтобы понять, какая стратегия лучше для вас, подумайте не о транзакциях в секунду, которые имеет ваша БД, а о продолжительности одной транзакции. Обычно вы открываете trasnaction, Performa Operation и закрываете транзакцию. Это короткая, классическая транзакция, которую ANSI имела в виду, и она прекрасно подходит для блокировки. Но как реализовать систему бронирования билетов, когда многие клиенты бронируют одни и те же номера / места одновременно?

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

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

При таком оптимистичном подходе вы должны записать все данные, которые вы прочитали (как в моем Повторном чтении ), и прийти к точке фиксации с вашей версией данных (я хочу покупать акции по цене, указанной в этой цитате, а не по текущей цене). ). На этом этапе создается транзакция ANSI, которая блокирует БД, проверяет, ничего не изменилось и фиксирует / прерывает вашу операцию. IMO, это эффективная эмуляция MVCC , которая также связана с Optimistic CC и также предполагает, что ваша транзакция перезапускается в случае сбоя, то есть вы сделаете новое резервирование. Транзакция здесь включает в себя решения пользователя.

Я далек от понимания того, как реализовать MVCC вручную, но я думаю, что длительные транзакции с возможностью перезапуска - ключ к пониманию предмета. Поправь меня, если я где-нибудь ошибаюсь. Мой ответ был мотивирован этой главой Алексея Кузнецова .

Маленький Чужой
источник
12

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

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

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

  • Оптимистическая блокировка полезна, если вероятность конфликтов очень мала - существует много записей, но относительно мало пользователей, или очень мало обновлений и в основном операций типа чтения.

Koenigsegg
источник
3

Один из вариантов использования оптимистической блокировки - это использование приложением базы данных, чтобы один из ваших потоков / хостов мог «требовать» выполнения задачи. Это метод, который мне пригодился на регулярной основе.

Лучший пример, который я могу придумать, - это очередь задач, реализованная с использованием базы данных, когда несколько потоков одновременно выполняют задачи. Если задача имеет статус «Доступно», «Заявлено», «Завершено», запрос БД может сказать что-то вроде «Установить статус =« Заявлено », где статус =« Доступно ». Если несколько потоков пытаются изменить статус таким способом, все, кроме первого потока, потерпят неудачу из-за грязных данных.

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

Чарли Кэмп
источник
3

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

При использовании оптимистической блокировки, мы должны быть осторожны с тем, как приложение восстановится после этих сбоев.

Особенно в асинхронных архитектурах, управляемых сообщениями, это может привести к неправильной обработке сообщений или к потере обновлений.

Сценарии отказов необходимо продумать.

Абхишек Шинде
источник