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

Shared state, як відомо необхідно захищати. Інакше паралельні потоки можуть його "поламати". Це відноситься і до web-додатків. Незважаючи на відсутність осудною підтримки паралелізму в більшості web-орієнтованих мов (PHP, Python, Ruby), concurrency в web-додатках вистачає. Запити приходять на web-сервер паралельно, виконуються на різних процесорах паралельно і т.д. З цієї причини наступний код некоректний:

Існує два принципово різних способу забезпечення цілісності даних: песимістична і оптимістична блокування. Песимістична блокування виходить з припущення, що якщо ми виконуємо код, конкурентна виконання якого може призвести до "поломки" даних, то необхідно виключити його конкурентну виконання. Тобто серіалізовать потоки в цій точці. Досягається це або за допомогою distributed lock'ов або транзакцій в БД.

У нас в системі є невелика бібліотека дозволяє реалізувати в коді виключає блокування. Її використання виглядає приблизно наступним чином:

Песимістична блокування схожа з принципом Мерфі. Вона передбачає, що якщо щось погане може статися, це обов'язково станеться. На відміну від песимістичної, оптимістична блокування передбачає що під час поновлення запису в БД ми будемо єдиними хто її змінює. У більшості випадків, так і є, так що оптимізм виправданий. Проте, під час UPDATE'а ми перевіряємо напевно змінилася запис з моменту її читання. І якщо змінилася, то ми зобов'язані прочитати останню версію запису з БД і повторити нашу операцію з нею.

Реалізація

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

В даному методі при оновленні ми перевіряємо, що версія не змінилася, а це значить, що і запис в БД ніхто не міняв. Якщо версія змінилася, ми зобов'язані сповістити про це клієнта.

Але тут є одна заковика. Що буде робити клієнт з цим exception'ом?

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

Переваги "оптимістів над песимістами"

Чи не блокує клієнтів, які не змінюють стан

Уявіть собі такий код:

Позбавляє клієнта від необхідності піклується про lock'ах

У разі оптимістичній блокування клієнтський код простіше і цього коду потрібно менше. Менше коду → менше проблем.

Гарантовано захищає дані

Коли ви оперуєте lock'амі можуть трапитися чотири типи проблем:

  • ви візьмете занадто мало локов (поламані дані);
  • ви візьмете занадто багато локов (deadlock. starvation);
  • ви візьмете не ті локи (поламані дані);
  • ви візьмете ті локи, але не в тому порядку (deadlock).

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

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

Що ви вибираєте?

Схожі статті