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


571

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

І чи змінюється відповідь на це запитання залежно від того, використовую чи ні я збережену процедуру для виконання запиту?

Але просто для перевірки оптимістичні засоби "не замикайте стіл під час читання", а песимістичний означає "замикайте стіл під час читання".



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 + ).


148
Оптимістичне блокування не обов'язково використовує номер версії. Інші стратегії включають використання (a) позначки часу або (b) всього стану самого рядка. Остання стратегія є некрасивою, але дозволяє уникнути необхідності виділення стовпця спеціальної версії у випадках, коли ви не можете змінити схему.
Ендрю Лебідь

2
@geek - Розподілені протоколи транзакцій, такі як XA, дозволяють окремий ідентифікатор транзакцій перешикуватися навколо однієї або декількох систем. Цей тип протоколу дозволяє використовувати блокування через об'єднані з'єднання, оскільки ідентифікатор транзакції від'єднується від сеансів і надається явно. Однак це має певні накладні витрати і схильні до витоку замків та ідентифікаторів транзакцій, якщо ваше додаток не дуже сумлінно відстежує їх. Це набагато більш важке рішення.
ЗанепокоєнийOfTunbridgeWells

22
@supercat - Не погоджуйтеся, що оптимістичне блокування є менш ніж на 100% точним - якщо воно перевіряє всі вхідні записи на транзакції, які повинні залишатися незмінними протягом тривалості, це так само точно, як песимістичне блокування (виберіть для стилю оновлення) для тих однакові записи. Основна відмінність полягає в тому, що оптимістичне блокування має накладні витрати лише у випадку конфлікту, тоді як песимістичне блокування зменшило накладні витрати на конфлікт. Тож оптимістичний варіант найкращий у випадку, коли більшість транзакцій не конфліктують - що, сподіваюся, зазвичай трапляється для більшості програм.
RichVel

2
@Legends - Використання оптимітичного блокування, безумовно, було б відповідною стратегією для веб-програми.
Занепокоєний

2
Слід зазначити, що вибір залежить також від співвідношення читання та запису: якщо ваша програма в основному є програмою для читання лише багатьма користувачами, а іноді ви записуєте дані, тоді йдіть на оптимістичне блокування. Наприклад, у StackOverflow багато людей читають сторінки, а іноді хтось редагує одну: у песимістичному блокуванні хто отримає замок? Перший? При оптимістичному блокуванні особа, яка бажає редагувати сторінку, може це робити, доки у неї є остання версія її.
jehon

177

Оптимістичне блокування використовується, коли ви не очікуєте багатьох зіткнень. Виконання звичайної операції коштує менше, але якщо зіткнення НЕ відбудеться, ви заплатите більшу ціну, щоб вирішити цю проблему, оскільки транзакція припиняється.

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

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


У звичайному випадку ця заява ідеальна, але в особливих випадках, коли ви могли керувати операцією CAS, дозволяючи неточність, як @skaffman згадується у відповіді, я б сказав, що це дійсно залежить.
Херен

75

Оптимістично припускає, що нічого не зміниться, коли ти читаєш це.

Песимістичний припускає, що щось буде і так блокує.

Якщо не суттєво, що дані ідеально читаються, використовуйте оптимістично. Ви можете отримати дивне "брудне" читання - але набагато рідше це призведе до тупиків і тому подібного.

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

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

Ну, і сервер Microsoft SQL за замовчуванням блокує сторінку - в основному це рядки, які ви читаєте, і кілька з обох сторін. Блокування рядків точніше, але набагато повільніше. Часто варто налаштувати транзакції на допущене читання чи без блокування, щоб уникнути тупикових ситуацій під час читання.


Оптимістичне блокування JPA дозволяє гарантувати послідовність читання.
Гілі

4
Консистенція читання - це окрема проблема - за допомогою PostgreSQL, Oracle та багатьох інших баз даних ви отримуєте послідовний перегляд даних незалежно від оновлень, які ще не здійснені, і на них не впливають навіть виключні блокування рядків.
RichVel

Я маю згоду з @RichVel. З одного боку, я бачу, як песимістичне блокування може запобігти забрудненню читання, якщо рівень ізоляції ваших транзакцій ЧИТАЙТЕ НЕЗАКОМНО. Але оманливим є твердження, що оптимістичне блокування чутливе до брудних зчитувань, не зазначаючи, що більшість баз даних (включаючи, очевидно, MS SQL Server) мають рівень ізоляції за замовчуванням "ЧИТАТИ ЗВ'ЯЗАНО", що запобігає брудному читанню та робить оптимістичне блокування таким же точним, як і песимістичний.
antinome

Ерік Броуер каже, що банкіри, на відміну від інших, віддають перевагу брудним операціям. Ваші гуру здаються абсолютно поза візками.
Маленький прибулець

1
Ерік Брюер - гуру, який дав теорему CAP говорить про послідовність у банківській справі . Це протилежне тому, за що ви його шануєте.
Маленький прибулець

50

Окрім сказаного вже:

  • Слід сказати, що optimisticблокування має тенденцію до підвищення одночасності за рахунок передбачуваності.
  • Pessimisticблокування має тенденцію до зниження одночасності, але є більш передбачуваним. Ви платите свої гроші тощо ...

3
Я не бачу, як передбачуваність (однак ви це визначите) покращується песимістичним блокуванням - якщо ви маєте на увазі "транзакція може завершитися, коли зроблено блокування", ви маєте рацію, але поки транзакція не отримає всіх необхідних блокувань, може виникнути затримка, щоб отримати залишилися блокування, і насправді вони можуть бути перервані через логіку виявлення тупикового блоку DB + логіку роздільної здатності. Програми, що використовують песимістичне блокування, можуть мати дуже непередбачувані часи виконання - класичний приклад - хтось блокує запис X, потім йде на обід, потім користувач блокує записи X і Y, потім ще Y і Z тощо, поки більшість користувачів не заблоковані. ..
RichVel

40

У вирішенні конфліктів у вас є два варіанти:

  • Ви можете спробувати уникнути конфлікту, і саме це робить песимістичне блокування.
  • Або ви можете дозволити виникнення конфлікту, але вам потрібно виявити його, здійснюючи транзакції, і саме це робить Optimistic Locking.

Тепер розглянемо наступну аномалію втраченого оновлення :

Втрачене оновлення

Аномалія втраченого оновлення може трапитися в програмі " Читає" рівня ізоляції.

На діаграмі вище ми бачимо, що Аліса вірить, що вона може зняти з неї 40 account але не усвідомлює, що Боб щойно змінив залишок на рахунку, і тепер у цьому обліковому записі залишилось лише 20.

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

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

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

На наведеній діаграмі і Аліса, і Боб придбають блокування читання на account рядку таблиці, яке читали обидва користувачі. База даних отримує ці блокування на SQL Server при використанні повторного читання або серіалізації.

Оскільки Аліса і Боб прочитали значення accountзі значенням ПК 1, жоден з них не може змінити його, поки один користувач не звільнить блокування читання. Це пов’язано з тим, що операція запису вимагає отримання блоку запису / ексклюзивного блокування, а спільні / читані блокування запобігають блокуванню запису / ексклюзивності.

Лише після того, як Аліса здійснила транзакцію, і блокування читання було випущено на accountрядок, Боб UPDATEвідновить і застосує зміни. Поки Аліса не звільнить блокування читання, оновлення Боб блокує.

Щоб дізнатися більше про те, як рамки доступу до даних використовують песимістичну підтримку блокування певної бази даних, перегляньте цю статтю .

Оптимістичне блокування

Оптимістичне блокування дозволяє виникнути конфлікт, але виявляє його, застосовуючи оновлення Аліси як зміну версії.

Операції на рівні додатків

Цього разу у нас є додаткова versionколонка. versionСтовпчика збільшується кожен раз , коли UPDATE або DELETE виконується, і він також використовується в реченні WHERE в UPDATE і DELETE заяви. Для цього нам потрібно видати SELECT і прочитати поточний versionперед виконанням UPDATE або DELETE, оскільки в іншому випадку ми б не знали, яке значення версії передавати до пункту WHERE або збільшувати.

Детальніше про те, як рамки доступу до даних реалізують оптимістичне блокування, ознайомтеся з цією статтею .

Операції на рівні додатків

Системи реляційних баз даних з'явилися в кінці 70-х - початку 80-х, коли клієнт, як правило, підключався до мейнфрейму через термінал. Ось чому ми все ще бачимо, як системи баз даних визначають такі терміни, як налаштування SESSION.

На сьогоднішній день через Інтернет ми більше не виконуємо читання та запис у контексті тієї самої транзакції бази даних, а ACID вже не є достатньою.

Наприклад, розглянемо такий випадок використання:

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

Без оптимістичного блокування немає жодного способу, як це втрачене оновлення було б спіймане, навіть якщо транзакції з базою даних використовували Serializable. Це відбувається тому, що читання та запис виконується в окремих HTTP-запитах, отже, в різних транзакціях бази даних.

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

Щоб отримати докладніші відомості про рівні програми або логічні транзакції, ознайомтеся з цією статтею .

Висновок

Оптимістичне блокування - дуже корисна методика, і вона працює чудово навіть при використанні менш суворих рівнів ізоляції, як, наприклад, читання Здійснено, або коли читання і запис виконуються в наступних транзакціях з базою даних.

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

Чим більше суперечок, тим більше конфліктів і тим більше шансів перервати транзакції. Зворотні звороти можуть бути дорогими для системи БД, оскільки вона потребує відновлення всіх поточних змін, що очікують на розгляд, які можуть включати як рядки таблиці, так і записи індексу.

З цієї причини песимістичне блокування може бути зручним, коли конфлікти трапляються часто, оскільки це зменшує ймовірність відхилення транзакцій.


Для яких сценаріїв ви б запропонували вибрати OptimisticLocking та PessimisticLocking? Чи залежить це від того, як часто виникає OptimisticLockException?
Кіт Стімпсона

1
Це залежить від випадку використання. Іноді оптимістичне блокування є єдиним рішенням (наприклад, транзакцій із кількома запитами). В інших випадках песимістичне блокування є єдиним рішенням (наприклад, дорадчі блокування PostgreSQL ). Іноді вам доводиться їх комбінувати, як це буває PESSIMISTIC_FORCE_INCREMENT.
Влад Михальча

22

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

Для оптимістичного блокування кожен учасник модифікації даних повинен погодитися з використанням такого типу блокування. Але якщо хтось модифікує дані, не піклуючись про стовпчик версій, це зіпсує всю ідею оптимістичного блокування.


Люди, які намагаються використовувати оптимістичне та песимістичне блокування, також можуть наступити один одному на ноги. Уявіть сценарій, коли оптимістичний сеанс читає запис і робить деякі обчислення, тоді як песимістичний сеанс оновлює запис, тоді оптимістичний сеанс повертається та оновлює цей самий запис, не помічаючи жодних змін. Виберіть ... для оновлення працює лише тоді, коли кожен сеанс використовує той самий синтаксис.
lusional

Добре пояснення, дайте голосувати за мене
Дулай Кулатунга

15

В основному є дві найпопулярніші відповіді. Перший один в основному говорить ,

Optimistic потребує трирівневої архітектури, де вам не обов'язково підтримувати з'єднання з базою даних для вашого сеансу, тоді як песимістичне блокування - це блокування запису для виключного використання, поки ви не закінчите з ним. Він має набагато кращу цілісність, ніж оптимістичне блокування, вам потрібно або безпосередньо підключення до бази даних.

Ще одна відповідь

оптимістичний (версія) швидший через відсутність блокування, але (песимістичний) блокування працює краще, коли суперечка висока, і краще запобігти роботі, а не відкидати її і починати спочатку.

або

Оптимістичне блокування найкраще спрацьовує при рідкісних зіткненнях

Як це розміщено на цій сторінці.

Я створив свою відповідь, щоб пояснити, як "підтримувати зв'язок" пов'язаний з "низькими зіткненнями".

Щоб зрозуміти, яка стратегія найкраще підходить вам, не думайте про транзакції за секунду, які має ваш БД, а тривалість однієї транзакції. Зазвичай ви відкриваєте транзакцію, перформацію та закриваєте транзакцію. Це коротка, класична транзакція, яку ANSI мав на увазі і добре, щоб уникнути блокування. Але як ви впроваджуєте систему бронювання квитків, коли багато клієнтів резервують однакові кімнати / місця одночасно?

Ви переглядаєте пропозиції, заповнюєте форму з великою кількістю доступних варіантів та поточними цінами. Це займає багато часу, і варіанти можуть застаріти. Усі ціни, недійсні між вами, ви почали заповнювати форму і натискати кнопку "Я згоден", тому що не було заблоковано дані, до яких ви зверталися, і хтось інший, більш спритний, втрутився змінивши всі ціни, і вам потрібно перезапустити нові ціни.

Ви можете замінити всі параметри, читаючи їх. Це песимістичний сценарій. Ви бачите, чому це смокче. Вашу систему може збити один клоун, який просто починає бронювати і курить. Ніхто не може зарезервувати нічого, перш ніж він закінчить. Ваш грошовий потік падає до нуля. Тому оптимістичні застереження використовуються в реальності. Тим, хто затримується занадто довго, доведеться відновити бронювання за вищими цінами.

При такому оптимістичному підході ви повинні записати всі прочитані вами дані (як у моєму повторному читанні ) та прийти до точки фіксації з вашою версією даних (я хочу купити акції за ціною, яку ви вказали в цій котируванні, а не поточній ціні ). У цей момент створюється транзакція ANSI, яка блокує БД, перевіряє, чи нічого не змінюється, і виконує / припиняє роботу. ІМО, це ефективна емуляція MVCC , яка також пов'язана з Optimistic CC, а також передбачає, що транзакція перезапуститься у разі переривання, тобто ви зробите нове застереження. Угода тут включає людські рішення.

Я далеко не розумію, як реалізувати MVCC вручну, але думаю, що тривалі операції з опцією перезавантаження є ключем до розуміння теми. Виправте мене, якщо я десь помиляюся. Мою відповідь мотивував цей розділ Алекс Кузнецов .


12

У більшості випадків оптимістичне блокування є більш ефективним та забезпечує більш високу продуктивність. Вибираючи між песимістичним та оптимістичним блокуванням, врахуйте наступне:

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

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

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


3

Один з випадків оптимістичного блокування - ваш додаток використовує базу даних, щоб дозволити одному з ваших потоків / хостів «претендувати» на завдання. Це техніка, яка мені стала в нагоді на регулярній основі.

Найкращий приклад, який я можу придумати, - це черга завдань, реалізована за допомогою бази даних, з декількома потоками, що вимагають виконання завдань одночасно. Якщо завдання має статус "Доступно", "Затверджено", "Виконано", запит на db може сказати щось на кшталт "Встановити статус =" Затверджено ", де статус =" Доступний ". Якщо кілька потоків намагаються змінити статус таким чином, все, окрім першого потоку, вийде з ладу через брудні дані.

Зауважте, що це випадок використання, що включає лише оптимістичне блокування. Тож як альтернатива тому, що "Оптимістичне блокування використовується, коли ви не очікуєте багатьох зіткнень", воно також може бути використане там, де ви очікуєте зіткнення, але хочете, щоб саме одна транзакція була успішною.


3

Про оптимістичне та песимістичне блокування було сказано багато хорошого. Важливим моментом, який слід врахувати, є наступне:

Використовуючи оптимістичне блокування, нам потрібно обережно ставитися до того, як додаток відновиться після цих збоїв.

Спеціально для асинхронних архітектур, керованих повідомленнями, це може призвести до непрацездатності обробки повідомлень або втрачених оновлень.

Сценарії відмов потрібно продумати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.