Zakleszczenia, blokady i MVCC
Jak bazy danych unikają konfliktów oraz kompromisy między blokadami a migawkami.
Zakleszczenia, blokady i MVCC to bezpłatna lekcja SQL Interview Prep na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej SQL Interview Prep, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.
Jak bazy danych faktycznie zapewniają izolację
Poziomy izolacji są obietnicą, a blokowanie i MVCC są mechanizmami, które ją realizują. Podczas rozmów rekrutacyjnych padają pytania na ten temat, aby sprawdzić, czy rozumieją Państwo, co dzieje się pod spodem, gdy transakcje wchodzą sobie w drogę.
Istnieją dwie główne strategie:
- Pesymistyczna (blokowanie): blokowanie sprzecznego dostępu do czasu zwolnienia blokady.
- Optymistyczna / MVCC: umożliwienie wszystkim odczytu spójnej migawki i wykrywanie konfliktów przy zatwierdzaniu transakcji.
Ta lekcja omawia blokady, zakleszczenia i MVCC, a także związane z nimi kompromisy.
Blokady współdzielone a wyłączne
Klasyczne blokowanie korzysta z dwóch głównych trybów:
- Blokada współdzielona (S) służy do odczytu. Wiele transakcji może jednocześnie utrzymywać blokadę współdzieloną na tym samym wierszu.
- Blokada wyłączna (X) służy do zapisu. Może ją posiadać tylko jedna transakcja, a blokuje ona wszystkie pozostałe blokady na tym wierszu.
Reguła jest następująca: S jest zgodna z S, ale X nie jest zgodna z żadną inną blokadą. Transakcja zapisująca musi zaczekać na wszystkich odczytujących, a odczytujący muszą zaczekać na transakcję zapisującą.
Jawne blokowanie za pomocą SELECT FOR UPDATE
Można zażądać blokady zapisu dla wierszy, które są tylko odczytywane, aby uniemożliwić innym transakcjom ich zmianę przed wykonaniem operacji. Jest to standardowy sposób unikania utraconych aktualizacji w cyklu odczyt–modyfikacja–zapis.
SELECT ... FOR UPDATE zakłada wyłączne blokady wierszy; wiersze pozostają zablokowane do wykonania COMMIT lub ROLLBACK.
BEGIN;
-- lock the row so no one else can modify it concurrently
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT; -- lock released hereCzym jest zakleszczenie
Zakleszczenie występuje, gdy co najmniej dwie transakcje posiadają blokady potrzebne drugiej transakcji, tworząc cykl, w którym żadna nie może kontynuować działania.
Klasyczny przypadek: T1 blokuje wiersz A, a następnie chce zablokować wiersz B; T2 blokuje wiersz B, a następnie chce zablokować wiersz A. Każda transakcja czeka w nieskończoność na drugą.
Bazy danych wykrywają takie sytuacje za pomocą grafu oczekiwania. Po wykryciu cyklu silnik wybiera ofiarę i przerywa jej działanie, zwracając błąd zakleszczenia, aby pozostałe transakcje mogły kontynuować pracę.
Zakleszczenie: oś czasu
Proszę obserwować krzyżującą się kolejność zakładania blokad. T1 blokuje wiersz 1, a następnie żąda blokady wiersza 2; T2 blokuje wiersz 2, a następnie żąda blokady wiersza 1. Żadna transakcja nie zwalnia blokady, więc silnik przerywa jedną z nich.
Przerwana transakcja otrzymuje błąd taki jak deadlock detected i musi ponowić próbę. Pozostała transakcja zatwierdza się normalnie.
-- T1 | -- T2
BEGIN; | BEGIN;
UPDATE accounts SET balance=balance-10 | UPDATE accounts SET balance=balance-10
WHERE id=1; -- locks row 1 | WHERE id=2; -- locks row 2
UPDATE accounts SET balance=balance+10 | UPDATE accounts SET balance=balance+10
WHERE id=2; -- waits for T2 | WHERE id=1; -- waits for T1 -> CYCLE
-- one transaction is chosen as victim and rolled backZapobieganie zakleszczeniom
Nie można całkowicie wyeliminować zakleszczeń, ale można sprawić, że będą występować rzadko. Standardowe odpowiedzi podczas rozmowy:
- Stała kolejność zakładania blokad: zawsze należy blokować wiersze w tej samej kolejności (na przykład według rosnącego id). Eliminuje to cykl.
- Krótkie transakcje: blokady powinny być utrzymywane możliwie krótko.
- Niższy poziom izolacji, gdy jest to bezpieczne: mniej blokad oznacza mniej konfliktów.
- Logika ponawiania prób: ofiary zakleszczeń powinny automatycznie ponawiać próbę.
Stała kolejność blokowania jest najskuteczniejszym rozwiązaniem i tym, o którym rozmówcy chcą usłyszeć w pierwszej kolejności.
Granularność blokad
Blokady można zakładać na różnych poziomach, co oznacza kompromis między współbieżnością a narzutem:
- Blokady na poziomie wiersza zapewniają wysoką współbieżność, ale wymagają większego nakładu na zarządzanie.
- Blokady na poziomie strony lub tabeli są tańsze w śledzeniu, ale blokują większą liczbę transakcji.
Niektóre silniki eskalują blokady z poziomu wierszy do poziomu tabeli, gdy transakcja dotyka zbyt wielu wierszy (eskalacja blokad). Wyjaśnia to, dlaczego duża zbiorcza instrukcja UPDATE może nagle zablokować wszystkich.
MVCC: podejście oparte na migawkach
MVCC (wielowersyjna kontrola współbieżności) to mechanizm, dzięki któremu Postgres, Oracle i InnoDB unikają większości blokad odczytu. Zamiast zakładać blokady, baza danych przechowuje wiele wersji każdego wiersza.
Najważniejsza korzyść, często przywoływana podczas rozmów rekrutacyjnych, brzmi: odczyty nie blokują zapisów, a zapisy nie blokują odczytów.
Każda transakcja widzi spójną migawkę stanu z określonego momentu, podczas gdy operacje zapisu tworzą nowe wersje wierszy zamiast nadpisywać je w miejscu.
Jak działa MVCC wewnątrz silnika
Po zaktualizowaniu wiersza MVCC zapisuje nową wersję i zachowuje starą. Każda wersja zawiera metadane z identyfikatorem transakcji (w Postgresie są to xmin i xmax), określające moment, w którym stała się widoczna, oraz moment, w którym została zastąpiona.
O tym, którą wersję widzi transakcja, decyduje jej migawka. Stare wersje, których żadna transakcja nie może już odczytać, stają się martwymi krotkami i są później odzyskiwane przez proces czyszczenia. W Postgresie ten proces to VACUUM; jego nieuruchamianie powoduje rozrost tabeli, o który często pada dodatkowe pytanie.
Blokowanie a MVCC: kompromis
Podsumujmy porównanie w skrócie:
- Czyste blokowanie: prosta gwarancja poprawności, ale odczyty i zapisy wzajemnie się blokują, co ogranicza współbieżność.
- MVCC: doskonała współbieżność odczytów i brak blokad odczytu, ale kosztem przechowywania wersji i ich czyszczenia (VACUUM, rozrost tabel); nadal potrzebne są także blokady przy konfliktach zapis-zapis.
Nawet silniki MVCC zakładają blokady podczas zapisu: dwie transakcje aktualizujące ten sam wiersz muszą wykonać te operacje szeregowo. MVCC eliminuje rywalizację odczyt-zapis, ale nie rywalizację zapis-zapis.
Optymistyczne blokowanie i kolumny wersji
Niezależnie od MVCC na poziomie silnika aplikacje często dodają optymistyczne blokowanie na potrzeby operacji odczyt–modyfikacja–zapis wykonywanych podczas długich sesji użytkownika. Należy dodać kolumnę version, odczytać jej wartość, a przy aktualizacji wymagać zgodności wersji i zwiększyć jej wartość.
Jeśli inna transakcja zaktualizowała wiersz wcześniej, wersje nie będą już zgodne, aktualizacja nie zmieni żadnego wiersza, a kod będzie wiedział, że należy ponownie wczytać dane i ponowić próbę. Podczas gdy użytkownik podejmuje decyzję, nie są utrzymywane żadne blokady, więc współbieżność pozostaje wysoka. Rozwiązanie to jest cenione podczas rozmów rekrutacyjnych jako odpowiedź na pytanie: „jak obsłużyć sytuację, gdy dwóch użytkowników edytuje ten sam rekord?”
-- read: SELECT id, data, version FROM items WHERE id = 1; -- version = 7
UPDATE items
SET data = 'new value', version = version + 1
WHERE id = 1 AND version = 7;
-- if rows affected = 0, someone else changed it: reload and retrySzybki test
Proszę sprawdzić kluczową zasadę MVCC.
Podsumowanie: blokady, zakleszczenia i MVCC
Można już wyjaśnić mechanizmy stojące za izolacją:
- Blokady współdzielone i wyłączne koordynują dostęp;
SELECT FOR UPDATEzakłada jawne blokady zapisu. - Zakleszczenia to cykle blokad; silnik przerywa działanie jednej z ofiar, a stała kolejność zakładania blokad zapobiega większości takich sytuacji.
- MVCC przechowuje wersje wierszy, dzięki czemu odczyty i zapisy nie blokują się wzajemnie, kosztem czyszczenia (VACUUM, rozrost tabel).
Połącz te mechanizmy z poziomami izolacji i anomaliami z wcześniejszych lekcji, a będziesz w stanie przeprowadzić pełną rozmowę techniczną na temat współbieżności od początku do końca.
Często zadawane pytania
Czy lekcja „Zakleszczenia, blokady i MVCC” jest bezpłatna?
Tak — pełny tekst „Zakleszczenia, blokady i MVCC” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu SQL Interview Prep, przejdź na CoddyKit PRO. Kurs SQL Interview Prep zawiera 4 lekcji w sumie.
Co nauczysz się w „Zakleszczenia, blokady i MVCC”?
Jak bazy danych unikają konfliktów oraz kompromisy między blokadami a migawkami. Ćwiczysz SQL Interview Prep z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć SQL Interview Prep?
Nie wymagamy żadnego doświadczenia. SQL Interview Prep w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Zakleszczenia, blokady i MVCC”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji SQL Interview Prep?
Tak. Każda lekcja SQL Interview Prep zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wyjaśnienie właściwości ACID
- Cztery poziomy izolacji
- Odczyty brudne, niepowtarzalne i fantomowe
- Zakleszczenia, blokady i MVCC