Udostępnij za pośrednictwem


Poziomy izolacji i konflikty zapisu w usłudze Azure Databricks

Poziom izolacji tabeli definiuje stopień, w jakim transakcja musi być odizolowana od modyfikacji wprowadzonych przez operacje współbieżne. Konflikty zapisu w Azure Databricks zależą od poziomu izolacji.

Delta Lake zapewnia gwarancje transakcji ACID między odczytami a zapisami. Oznacza to, że:

  • Wielu pisarzy w różnych klastrach może jednocześnie modyfikować partycję tabeli. Autorzy widzą spójny widok migawki tabeli i zapisy występują w kolejności szeregowej.
    • Czytelnicy nadal widzą spójny widok migawki tabeli, z którą uruchomiono zadanie usługi Azure Databricks, nawet jeśli tabela jest modyfikowana podczas zadania.

Zobacz Co to są gwarancje ACID w usłudze Azure Databricks?.

Uwaga

Usługa Azure Databricks domyślnie używa usługi Delta Lake dla wszystkich tabel. W tym artykule opisano zachowanie usługi Delta Lake w usłudze Azure Databricks.

Ważne

Zmiany metadanych powodują niepowodzenie wszystkich współbieżnych operacji zapisu. Te operacje obejmują zmiany protokołu tabeli, właściwości tabeli lub schematu danych.

Odczyty strumieniowe kończą się niepowodzeniem, gdy napotkają operację zatwierdzenia zmieniającą metadane tabeli. Jeśli chcesz, aby strumień kontynuował, musisz uruchomić go ponownie. Aby zapoznać się z zalecanymi metodami, zobacz Zagadnienia produkcji dla strukturalnego przesyłania strumieniowego.

Poniżej przedstawiono przykłady zapytań, które zmieniają metadane:

-- Set a table property.
ALTER TABLE table-name SET TBLPROPERTIES ('delta.isolationLevel' = 'Serializable')

-- Enable a feature using a table property and update the table protocol.
ALTER TABLE table_name SET TBLPROPERTIES ('delta.enableDeletionVectors' = true);

-- Drop a table feature.
ALTER TABLE table_name DROP FEATURE deletionVectors;

-- Upgrade to UniForm.
REORG TABLE table_name APPLY (UPGRADE UNIFORM(ICEBERG_COMPAT_VERSION=2));

-- Update the table schema.
ALTER TABLE table_name ADD COLUMNS (col_name STRING);

Konflikty zapisu ze współbieżnością na poziomie wiersza

Współbieżność na poziomie wiersza zmniejsza konflikty między współbieżnymi operacjami zapisu, wykrywając zmiany na poziomie wiersza i automatycznie rozwiązując konflikty, które występują, gdy współbieżne zapisy aktualizują lub usuwają różne wiersze w tym samym pliku danych.

Współbieżność na poziomie wiersza jest ogólnie dostępna w środowisku Databricks Runtime 14.2 lub nowszym. Współbieżność na poziomie wiersza jest domyślnie obsługiwana dla następujących warunków:

  • Tabele z włączonymi wektorami usuwania, bez partycjonowania.
  • Tabele z klastrowaniem płynnym, chyba że wyłączono wektory usuwania.

Tabele z partycjami nie obsługują jednoczesnego dostępu na poziomie wiersza, ale nadal mogą unikać konfliktów między OPTIMIZE a wszystkimi innymi operacjami zapisu po włączeniu wektorów usuwania. Zobacz Ograniczenia dotyczące współbieżności na poziomie wiersza.

Aby uzyskać informacje o innych wersjach środowiska Databricks Runtime, zobacz Zachowanie podglądu współbieżności na poziomie wiersza (starsza wersja).

MERGE INTO Obsługa współbieżności na poziomie wiersza wymaga aplikacji Photon w środowisku Databricks Runtime 14.2. W środowisku Databricks Runtime 14.3 LTS i nowszym aplikacja Photon nie jest wymagana.

W poniższej tabeli opisano, które pary operacji zapisu mogą powodować konflikty na każdym poziomie izolacji z włączoną współbieżnością na poziomie wiersza.

Uwaga

Tabele z kolumnami tożsamości nie obsługują transakcji współbieżnych. Zobacz Korzystanie z kolumn tożsamości w Delta Lake.

INSERT (1) UPDATE, USUŃ, MERGE INTO OPTIMIZE
INSERT Nie może być konfliktu
UPDATEUSUNĄĆ MERGE INTO Nie może wystąpić konflikt w WriteSerializable. Może powodować konflikt w przypadku serializacji podczas modyfikowania tego samego wiersza. Zobacz Ograniczenia dotyczące współbieżności na poziomie wiersza. Może powodować konflikt podczas modyfikowania tego samego wiersza. Zobacz Ograniczenia dotyczące współbieżności na poziomie wiersza.
OPTIMIZE Nie może być konfliktu Może powodować konflikt, gdy ZORDER BY jest używany. Inaczej nie może dojść do konfliktu. Może powodować konflikt, gdy ZORDER BY jest używany. Inaczej nie może dojść do konfliktu.

Ważne

(1) Wszystkie INSERT operacje w tabelach powyżej opisują operacje dołączania, które nie odczytują żadnych danych z tej samej tabeli przed ich zatwierdzeniem. INSERT operacje zawierające podzapytania odczytujące tę samą tabelę obsługują tę samą współbieżność co MERGE.

REORG operacje mają semantykę izolacji identyczną z OPTIMIZE podczas ponownego zapisu plików danych w celu odzwierciedlenia zmian zarejestrowanych w wektorach usuwania. W przypadku zastosowania REORG uaktualnienia, protokoły tabel zmieniają się, co stwarza konflikt ze wszystkimi trwającymi operacjami.

Konflikty zapisu bez współbieżności na poziomie poszczególnych wierszy

W poniższej tabeli opisano, które pary operacji zapisu mogą powodować konflikty na każdym poziomie izolacji.

Tabele nie obsługują współbieżności na poziomie wiersza, jeśli mają zdefiniowane partycje lub nie mają włączonych wektorów usuwania. Środowisko Databricks Runtime 14.2 lub nowsze jest wymagane do współbieżności na poziomie wiersza.

Uwaga

Tabele z kolumnami tożsamości nie obsługują transakcji współbieżnych. Zobacz Korzystanie z kolumn tożsamości w Delta Lake.

INSERT (1) UPDATE, USUŃ, MERGE INTO OPTIMIZE
INSERT Nie może być konfliktu
UPDATEUSUNĄĆ MERGE INTO Nie może wystąpić konflikt w WriteSerializable. Może powodować konflikt w ramach Serializable. Zobacz Unikanie konfliktów z partycjami. Może wystąpić konflikt pomiędzy Serializable a WriteSerializable. Zobacz Unikanie konfliktów z partycjami.
OPTIMIZE Nie może być konfliktu Nie można powodować konfliktów z tabelami z włączonymi wektorami usuwania, chyba że użyto ZORDER BY. W przeciwnym razie może powodować konflikt. Nie można powodować konfliktów z tabelami z włączonymi wektorami usuwania, chyba że użyto ZORDER BY. W przeciwnym razie może powodować konflikt.

Ważne

(1) Wszystkie INSERT operacje w tabelach powyżej opisują operacje dołączania, które nie odczytują żadnych danych z tej samej tabeli przed ich zatwierdzeniem. INSERT operacje zawierające podzapytania odczytujące tę samą tabelę obsługują tę samą współbieżność co MERGE.

REORG operacje mają semantykę izolacji identyczną z OPTIMIZE podczas ponownego zapisu plików danych w celu odzwierciedlenia zmian zarejestrowanych w wektorach usuwania. W przypadku zastosowania REORG uaktualnienia, protokoły tabel zmieniają się, co stwarza konflikt ze wszystkimi trwającymi operacjami.

Ograniczenia współbieżności na poziomie wiersza

Niektóre ograniczenia dotyczą współbieżności na poziomie wiersza. W przypadku następujących operacji rozwiązywanie konfliktów odbywa się zgodnie z trybem normalnej współbieżności dla konfliktów zapisu w usłudze Azure Databricks. Zobacz Konflikty zapisu przy braku współbieżności na poziomie wierszy.

  • Polecenia ze złożonymi klauzulami warunkowymi, w tym następujące:
    • Warunki dotyczące złożonych typów danych, takich jak struktury, tablice lub mapy.
    • Warunki używające wyrażeń niedeterministycznych i podzapytania.
    • Warunki zawierające skorelowane podzapytania.
  • W środowisku Databricks Runtime 14.2 MERGE polecenia muszą używać jawnego predykatu w tabeli docelowej do filtrowania wierszy pasujących do tabeli źródłowej. W przypadku rozwiązywania konfliktów przy scalaniu filtr skanuje tylko te wiersze, które mogą powodować konflikt na podstawie warunków filtrowania w operacjach współbieżnych.

Uwaga

Wykrywanie konfliktów na poziomie wiersza może zwiększyć całkowity czas wykonywania. W przypadku wielu równoczesnych transakcji składnik zapisywania nadaje priorytet opóźnieniom ponad rozwiązywanie konfliktów i mogą wystąpić konflikty.

Obowiązują również wszystkie ograniczenia dotyczące wektorów usuwania. Zobacz Ograniczenia.

Kiedy Delta Lake zatwierdza zmiany bez odczytywania tabeli?

Operacje Delta Lake INSERT lub dodawania nie odczytują stanu tabeli przed zatwierdzeniem, jeśli spełnione są następujące warunki:

  1. Logika jest wyrażana przy użyciu INSERT logiki SQL lub trybu dołączania.
  2. Logika nie zawiera podzapytania ani warunkowych odwołujących się do tabeli objętej operacją zapisu.

Podobnie jak w przypadku innych zatwierdzeń, Delta Lake weryfikuje i rozpoznaje wersje tabeli przy użyciu metadanych w dzienniku transakcji, ale żadna wersja tabeli nie jest faktycznie odczytywana.

Uwaga

Wiele typowych wzorców używa operacji MERGE do wstawiania danych na podstawie warunków zawartych w tabeli. Chociaż może być możliwe ponowne zapisywanie tej logiki przy użyciu INSERT instrukcji, jeśli dowolne wyrażenie warunkowe odwołuje się do kolumny w tabeli docelowej, te instrukcje mają takie same ograniczenia współbieżności jak MERGE.

Zapisuj możliwe do serializacji i możliwe do serializacji poziomy izolacji

Poziom izolacji tabeli definiuje stopień, w jakim transakcja musi być odizolowana od modyfikacji wprowadzonych przez transakcje współbieżne. Delta Lake w usłudze Azure Databricks obsługuje dwa poziomy izolacji: Serializable i WriteSerializable.

  • Serializowalny: najsilniejszy poziom izolacji. Gwarantuje to, że zatwierdzone operacje zapisu i wszystkie operacje odczytu są serializowalne. Operacje są dozwolone tak długo, jak istnieje sekwencja szeregowa wykonywania ich jednorazowo, która generuje taki sam wynik jak w tabeli. W przypadku operacji zapisu sekwencja szeregowa jest dokładnie taka sama jak w historii tabeli.

  • WriteSerializable (wartość domyślna): słabszy poziom izolacji niż Serializowalny. Gwarantuje to tylko, że operacje zapisu (czyli nie odczyty) można serializować. Jest to jednak nadal silniejsze niż izolacja migawki . WriteSerializable jest domyślnym poziomem izolacji, ponieważ zapewnia doskonałą równowagę spójności danych i dostępności dla najbardziej typowych operacji.

    W tym trybie zawartość tabeli Delta może się różnić od tej, która wynika z sekwencji operacji widocznych w historii tabeli. Dzieje się tak dlatego, że ten tryb umożliwia wykonywanie niektórych par współbieżnych zapisów (np. operacji X i Y), tak aby wynik wyglądał, jakby Y zostało wykonane przed X (czyli serializowany między nimi), mimo że historia wykazywałaby, że Y został zatwierdzony po X. Aby uniemożliwić takie zmienianie kolejności, ustaw poziom izolacji tabeli na Serializowalny, aby te transakcje się nie powiodły.

Operacje odczytu zawsze używają izolacji migawki. Poziom izolacji zapisu określa, czy czytelnik może zobaczyć widok tabeli, który według historii "nigdy nie istniał".

W przypadku poziomu z możliwością serializacji czytelnik zawsze widzi tylko tabele zgodne z historią. Na poziomie WriteSerializable czytelnik może widzieć tabelę, która nie istnieje w dzienniku Delta.

Rozważmy na przykład txn1, długotrwałą operację usuwania i txn2, która wstawia dane usunięte przez txn1. txn2 i txn1 są zakończone i zostają zapisane w historii, zachowując tę kolejność. Zgodnie z historią dane wstawione w txn2 nie powinny istnieć w tabeli. W przypadku poziomu z możliwością serializacji czytnik nigdy nie widziałby danych wstawionych przez txn2. Jednak na poziomie WriteSerializable czytnik może w pewnym momencie zobaczyć dane wstawione przez txn2.

Aby uzyskać więcej informacji na temat typów operacji, które mogą wchodzić w konflikt ze sobą na każdym poziomie izolacji oraz możliwych błędów, zobacz Unikanie konfliktów przy użyciu partycjonowania i rozłącznych warunków poleceń.

Ustawianie poziomu izolacji

Poziom izolacji można ustawić przy użyciu ALTER TABLE polecenia .

ALTER TABLE <table-name> SET TBLPROPERTIES ('delta.isolationLevel' = <level-name>)

gdzie <level-name> to Serializable lub WriteSerializable.

Aby na przykład zmienić poziom izolacji z domyślnego WriteSerializable na Serializable, uruchom polecenie:

ALTER TABLE <table-name> SET TBLPROPERTIES ('delta.isolationLevel' = 'Serializable')

Unikaj konfliktów, stosując partycjonowanie i rozłączne warunki polecenia

We wszystkich przypadkach oznaczonych jako "może powodować konflikt", czy te dwie operacje będą powodować konflikt, zależy od tego, czy działają one na tym samym zestawie plików. Dwa zestawy plików można rozdzielić, partycjonując tabelę według tych samych kolumn, które są używane w warunkach operacji. Na przykład dwa polecenia UPDATE table WHERE date > '2010-01-01' ... i DELETE table WHERE date < '2010-01-01' będą powodować konflikt, jeśli tabela nie jest partycjonowana według daty, ponieważ obie mogą próbować zmodyfikować ten sam zestaw plików. Partycjonowanie tabeli przez date spowoduje uniknięcie konfliktu. W związku z tym partycjonowanie tabeli zgodnie z często używanymi warunkami występującymi w poleceniu może znacznie zmniejszyć konflikty. Jednak partycjonowanie tabeli według kolumny o wysokiej kardynalności może prowadzić do innych problemów z wydajnością z powodu dużej liczby podkatalogów.

Wyjątki od konfliktów

Kiedy wystąpi konflikt transakcji, zaobserwujesz jeden z następujących wyjątków:

ConcurrentAppendException

Wyjątek ten występuje, gdy współbieżna operacja dodaje pliki w tej samej partycji (lub w dowolnym miejscu w niepartycjonowanej tabeli), którą odczytuje operacja. Dodatki plików mogą być spowodowane operacjami INSERT, DELETE, UPDATElub MERGE .

Przy domyślnym poziomie izolacjiWriteSerializable, pliki dodane przez operacje blind (czyli operacje, które ślepo dołączają dane bez odczytywania żadnych danych) nie powodują konfliktu z żadną operacją, nawet jeśli dotykają tej samej partycji (lub w dowolnym miejscu w niepartycjonowanej tabeli). Jeśli poziom izolacji jest ustawiony na Serializable, wtedy niewidome dołączanie może powodować konflikt.

Ważne: ślepe dodawanie może powodować konflikt w trybie WriteSerializable, jeśli wiele współbieżnych transakcji równocześnie przeprowadzających operacje DELETE, UPDATElub MERGE może odwoływać się do wartości wstawionych przez ślepe dodawanie. Aby uniknąć tego konfliktu, wykonaj jedną z następujących czynności:

  • Upewnij się, że operacje współbieżne DELETE, UPDATElub MERGE nie odczytują dołączonych danych.
  • Mieć co najwyżej jedną operację DELETE, UPDATElub MERGE, która może odczytywać dołączone dane.

Ten wyjątek jest często zgłaszany podczas współbieżnych operacji DELETE, operacji UPDATE lub operacji MERGE. Podczas gdy operacje współbieżne mogą fizycznie aktualizować różne katalogi partycji, jedna z nich może odczytywać tę samą partycję, którą druga współbieżnie aktualizuje, powodując w ten sposób konflikt. Możesz tego uniknąć, wyraźnie zaznaczając separację w warunku operacji. Rozważmy następujący przykład.

// Target 'deltaTable' is partitioned by date and country
deltaTable.as("t").merge(
    source.as("s"),
    "s.user_id = t.user_id AND s.date = t.date AND s.country = t.country")
  .whenMatched().updateAll()
  .whenNotMatched().insertAll()
  .execute()

Załóżmy, że uruchamiasz powyższy kod współbieżnie dla różnych dat lub krajów. Ponieważ każde zadanie pracuje nad niezależną partycją w docelowej tabeli Delta, nie spodziewasz się żadnych konfliktów. Jednak warunek nie jest wystarczająco wyraźny i może skanować całą tabelę i może kolidować z współbieżnymi operacjami aktualizującymi inne partycje. Zamiast tego możesz przepisać instrukcję, aby dodać określoną datę i kraj do warunku scalania, jak pokazano w poniższym przykładzie.

// Target 'deltaTable' is partitioned by date and country
deltaTable.as("t").merge(
    source.as("s"),
    "s.user_id = t.user_id AND s.date = t.date AND s.country = t.country AND t.date = '" + <date> + "' AND t.country = '" + <country> + "'")
  .whenMatched().updateAll()
  .whenNotMatched().insertAll()
  .execute()

Operacja ta może być teraz bezpiecznie przeprowadzana współbieżnie w różnych terminach i krajach.

ConcurrentDeleteReadException

Ten wyjątek występuje, gdy operacja współbieżna usunęła plik odczytany przez operację. Typowe przyczyny to operacja DELETE, UPDATE lub MERGE, która ponownie zapisuje pliki.

ConcurrentDeleteDeleteException

Ten wyjątek występuje, gdy operacja współbieżna usunęła plik, który operacja również usuwa. Może to być spowodowane przez dwie współbieżne operacje kompaktowania przepisujące te same pliki.

MetadataChangedException

Ten wyjątek występuje, gdy współbieżna transakcja aktualizuje metadane tabeli delty. Typowe przyczyny to operacje ALTER TABLE lub zapisy w tabeli Delta, które mogą aktualizować schemat tabeli.

ConcurrentTransactionException

Jeśli zapytanie przesyłane strumieniowo przy użyciu tej samej lokalizacji punktu kontrolnego jest uruchamiane wiele razy jednocześnie i próbuje zapisać w tabeli delty w tym samym czasie. Dwa zapytania strumieniowe nigdy nie powinny korzystać z tej samej lokalizacji punktu kontrolnego i działać w tym samym czasie.

ProtocolChangedException (WyjątekZmianyProtokołu)

Ten wyjątek może wystąpić w następujących przypadkach:

  • Po uaktualnieniu tabeli delty do nowej wersji protokołu. Aby przyszłe operacje zakończyły się powodzeniem, może być konieczne uaktualnienie środowiska Databricks Runtime.
  • Kiedy wielu autorów tworzy lub zastępuje tabelę w tym samym czasie.
  • Gdy wielu autorów zapisuje dane na pustej ścieżce jednocześnie.

Aby uzyskać więcej informacji, zobacz zgodność funkcji i protokoły systemu Delta Lake.

Zachowanie podglądu współbieżności na poziomie wiersza (starsza wersja)

W tej sekcji opisano zachowania podglądu współbieżności na poziomie wiersza w środowisku Databricks Runtime 14.1 lub nowszym. Współbieżność na poziomie wiersza zawsze wymaga wektorów usuwania.

W środowisku Databricks Runtime 13.3 LTS lub nowszym tabele z włączonym klastrowaniem płynnym automatycznie włączają współbieżność na poziomie wiersza.

W środowisku Databricks Runtime 14.0 i 14.1 można włączyć współbieżność na poziomie wierszy dla tabel z wektorami usuwania, ustawiając następującą konfigurację klastra lub SparkSession:

spark.databricks.delta.rowLevelConcurrencyPreview = true

W środowisku Databricks Runtime 14.1 lub nowszym obliczenia inne niż photon obsługują tylko współbieżność na poziomie wiersza dla DELETE operacji.