Sdílet prostřednictvím


Úrovně izolace a konflikty zápisu v Azure Databricks

Úroveň izolace tabulky definuje stupeň, do kterého musí být transakce izolovaná od úprav provedených souběžnými operacemi. Konflikty zápisu v Azure Databricks závisí od úrovně izolace.

Delta Lake poskytuje záruky transakcí ACID mezi čtením a zápisem. To znamená, že:

  • Různí autoři mohou současně upravovat oddíl tabulky v různých clusterech. Pisatelé vidí konzistentní snímek tabulky a zápisy probíhají v sériovém pořadí.
    • Čtenáři i nadále uvidí konzistentní zobrazení snímku tabulky, se kterou začala úloha Azure Databricks, i když se během úlohy změní tabulka.

Podívejte se, co jsou záruky ACID v Azure Databricks?

Poznámka:

Azure Databricks ve výchozím nastavení používá Delta Lake pro všechny tabulky. Tento článek popisuje chování Delta Lake v Azure Databricks.

Důležité

Změny metadat způsobují selhání všech souběžných operací zápisu. Mezi tyto operace patří změny tabulkového protokolu, vlastností tabulky nebo schématu dat.

Streamované čtení selže, když narazí na potvrzení, které změní metadata tabulky. Pokud chcete, aby datový proud pokračoval, musíte ho restartovat. Doporučené metody najdete v tématu Důležité informace o produkčním prostředí pro strukturované streamování.

Tady jsou příklady dotazů, které mění metadata:

-- 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 zápisu se souběžností na úrovni řádků

Souběžnost na úrovni řádků snižuje konflikty mezi souběžnými operacemi zápisu tím, že detekuje změny na úrovni řádků a automaticky řeší konflikty, ke kterým dochází při souběžné aktualizaci zápisu nebo odstranění různých řádků ve stejném datovém souboru.

Souběžnost na úrovni řádků je obecně dostupná pro Databricks Runtime 14.2 a vyšší. Souběžnost na úrovni řádků je ve výchozím nastavení podporovaná pro následující podmínky:

  • Tabulky s povolenými vektory odstranění a bez particionování
  • Tabulky s clusteringem tekutin, pokud nemáte deaktivovány vektory pro odstranění.

Tabulky s oddíly nepodporují souběžnost na úrovni řádků, ale mohou se vyhnout konfliktům mezi OPTIMIZE a všemi ostatními operacemi zápisu při povolení vektorů odstranění. Viz Omezení souběžnosti na úrovni řádků.

Pro jiné verze Databricks Runtime vizte Chování na úrovni řádků v režimu souběžnosti (starší verze).

MERGE INTO Podpora souběžnosti na úrovni řádků vyžaduje Photon v Databricks Runtime 14.2. Ve službě Databricks Runtime 14.3 LTS a novější není Photon vyžadován.

Následující tabulka popisuje, které páry operací zápisu můžou kolidovat v každé úrovni izolace s povolenou souběžností na úrovni řádků.

Poznámka:

Tabulky se sloupci identit nepodporují souběžné transakce. Viz Použití sloupců identit v Delta Lake.

INSERT (1) UPDATEVYMAZATMERGE INTO OPTIMIZE
INSERT Nemůže být v rozporu
UPDATEVYMAZAT MERGE INTO Nelze zpracovat konflikt v WriteSerializable. Při úpravě stejného řádku může dojít ke konfliktu v režimu Serializable. Viz Omezení souběžnosti na úrovni řádků. Může dojít ke konfliktu při úpravě stejného řádku. Viz Omezení souběžnosti na úrovni řádků.
OPTIMIZE Nemůže být v rozporu Může dojít ke konfliktu použitím ZORDER BY. Nemůže to být v rozporu jinak. Může dojít ke konfliktu použitím ZORDER BY. Nemůže to být v rozporu jinak.

Důležité

(1) Všechny INSERT operace v tabulkách výše popisují připojovací operace, které nepřečtou žádná data ze stejné tabulky před potvrzením. INSERT operace, které obsahují poddotazy, které čtou stejnou tabulku, podporují stejnou souběžnost jako MERGE.

REORG operace mají sémantiku izolace stejnou jako OPTIMIZE při přepsání datových souborů tak, aby odrážely změny zaznamenané ve vektorech odstranění. Když použijete REORG ke spuštění upgradu, dojde ke změně protokolů tabulek, což je v rozporu se všemi probíhajícími operacemi.

Konflikty zápisu při absenci konkurence na úrovni řádků

Následující tabulka popisuje, které páry operací zápisu můžou kolidovat v jednotlivých úrovních izolace.

Tabulky nepodporují souběžnost na úrovni řádků, pokud mají definované oddíly nebo nemají povolené vektory odstranění. Databricks Runtime 14.2 nebo vyšší se vyžaduje pro souběžnost na úrovni řádků.

Poznámka:

Tabulky se sloupci identit nepodporují souběžné transakce. Viz Použití sloupců identit v Delta Lake.

INSERT (1) UPDATEVYMAZATMERGE INTO OPTIMIZE
INSERT Nemůže být v rozporu
UPDATEVYMAZAT MERGE INTO Nelze zpracovat konflikt v WriteSerializable. Může být v konfliktu se serializovatelností. Viz vyhnout se konfliktům s oddíly. Může dojít ke konfliktu v Serializable a WriteSerializable. Viz vyhnout se konfliktům s oddíly.
OPTIMIZE Nemůže být v rozporu Nelze dojít ke konfliktu s tabulkami, ve kterých jsou zapnuté vektory odstranění, pokud není použit ZORDER BY. Může se dostat do konfliktu jinak. Nelze dojít ke konfliktu s tabulkami, ve kterých jsou zapnuté vektory odstranění, pokud není použit ZORDER BY. Může se dostat do konfliktu jinak.

Důležité

(1) Všechny INSERT operace v tabulkách výše popisují připojovací operace, které nepřečtou žádná data ze stejné tabulky před potvrzením. INSERT operace, které obsahují poddotazy, které čtou stejnou tabulku, podporují stejnou souběžnost jako MERGE.

REORG operace mají sémantiku izolace stejnou jako OPTIMIZE při přepsání datových souborů tak, aby odrážely změny zaznamenané ve vektorech odstranění. Když použijete REORG ke spuštění upgradu, dojde ke změně protokolů tabulek, což je v rozporu se všemi probíhajícími operacemi.

Omezení souběžnosti na úrovni řádků

Některá omezení se vztahují na souběžnost na úrovni řádků. Pro následující operace se řešení konfliktů řídí běžným způsobem souběžného zpracování pro konflikty zápisu v Azure Databricks. Viz Konflikty zápisu bez souběžnosti na úrovni řádků.

  • Příkazy se složitými podmíněnými klauzulemi, včetně následujících:
    • Podmínky pro komplexní datové typy, jako jsou struktury, pole nebo mapy.
    • Podmínky používající ne deterministické výrazy a poddotazy
    • Podmínky, které obsahují korelované poddotazy.
  • V Databricks Runtime 14.2 MERGE musí příkazy použít explicitní predikát v cílové tabulce k filtrování řádků odpovídajících zdrojové tabulce. V případě řešení sloučení filtr prohledá pouze řádky, které můžou být v konfliktu na základě podmínek filtru v souběžných operacích.

Poznámka:

Detekce konfliktů na úrovni řádků může zvýšit celkovou dobu provádění. V případě mnoha souběžných transakcí zapisovač upřednostňuje latenci před řešením konfliktů a může dojít ke konfliktům.

Platí také všechna omezení pro vektory odstranění. Viz Omezení.

Kdy Delta Lake provádí změny bez čtení tabulky?

Operace Delta Lake INSERT nebo operace připojení nečtou stav tabulky před potvrzením, pokud jsou splněny následující podmínky:

  1. Logika se vyjadřuje pomocí INSERT logiky SQL nebo režimu připojení.
  2. Logika neobsahuje žádné poddotazy ani podmíněné výrazy, které odkazují na tabulku cílenou operací zápisu.

Stejně jako v jiných případech potvrzení Delta Lake ověřuje a řeší verze tabulek během potvrzení pomocí metadat v transakčním protokolu, ale ve skutečnosti se žádná verze tabulky nečte.

Poznámka:

Mnoho běžných vzorů používá MERGE operace k vkládání dat na základě podmínek tabulky. I když může být možné přepsat tuto logiku pomocí INSERT příkazů, pokud některé podmíněné výrazy odkazují na sloupec v cílové tabulce, mají tyto příkazy stejná omezení souběžnosti jako MERGE.

Zápis serializovatelných vs. serializovatelných úrovní izolace

Úroveň izolace tabulky definuje stupeň, do kterého musí být transakce izolovaná od úprav provedených souběžnými transakcemi. Delta Lake v Azure Databricks podporuje dvě úrovně izolace: Serializable a WriteSerializable.

  • Serializovatelné: Nejsilnější úroveň izolace. Zajišťuje, že potvrzené operace zápisu a všechna čtení jsou serializovatelná. Operace jsou povoleny, pokud existuje sériová posloupnost jejich jednorázového spuštění, která generuje stejný výsledek jako v tabulce. V případě operací zápisu je sériová sekvence úplně stejná jako v historii tabulky.

  • WriteSerializable (Výchozí): Slabší úroveň izolace než serializovatelná. Zajišťuje pouze, že operace zápisu (tj. ne čtení) jsou serializovatelné. Je to ale stále silnější než izolace snímků . WriteSerializable je výchozí úroveň izolace, protože poskytuje skvělou rovnováhu mezi konzistencí dat a dostupností pro nejběžnější operace.

    V tomto režimu se obsah tabulky Delta může lišit od toho, co se očekává od posloupnosti operací zobrazených v historii tabulek. Důvodem je to, že tento režim umožňuje určitým párům souběžných zápisů (například operací X a Y) pokračovat tak, aby výsledek byl stejný, jako kdyby byl Y proveden před X (tj. serializovatelný mezi nimi), i když historie by ukázala, že Y byl potvrzen po X. Pokud chcete toto změny pořadí zakázat, nastavte úroveň izolace tabulky tak, aby byla Serializovatelná, aby tyto transakce selhaly.

Operace čtení vždy používají izolaci snímků. Úroveň izolace zápisu určuje, zda je možné, aby čtenář viděl snímek tabulky, který podle historie „nikdy neexistoval“.

Pro serializovatelnou úroveň čtenář vždy vidí pouze tabulky, které odpovídají historii. Pro úroveň WriteSerializable může čtenář vidět tabulku, která v protokolu Delta neexistuje.

Představte si například txn1, dlouho trvající mazání, a txn2, které vkládá data odstraněná txn1. txn2 a txn1 jsou dokončeny a zaznamenány v tomto pořadí v historii. Podle historie by data vložená v txn2 neměla v tabulce existovat. V případě serializovatelné úrovně by čtečka nikdy neviděla data vložená pomocí txn2. Pro úroveň WriteSerializable však čtenář může v určitém okamžiku vidět data vložená pomocí txn2.

Další informace o tom, které typy operací můžou vzájemně kolidovat v jednotlivých úrovních izolace a možné chyby, najdete v tématu Zabránění konfliktům pomocí dělení a nesouvislých podmínek příkazů.

Nastavení úrovně izolace

Úroveň izolace nastavíte pomocí ALTER TABLE příkazu.

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

kde <level-name> je Serializable nebo WriteSerializable.

Pokud chcete například změnit úroveň izolace z výchozí WriteSerializableSerializablena , spusťte:

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

Vyhněte se konfliktům pomocí podmínek dělení a oddělených příkazů

Ve všech případech označených jako "může kolidovat", zda tyto dvě operace budou kolidovat, závisí na tom, jestli pracují se stejnou sadou souborů. Tyto dvě sady souborů můžete rozdělit tak, že tabulku rozdělíte podle stejných sloupců, které se používají v podmínkách operací. Například dva příkazy UPDATE table WHERE date > '2010-01-01' ... a DELETE table WHERE date < '2010-01-01' budou v konfliktu, pokud tabulka není rozdělena podle data, protože oba se mohou pokusit upravit stejnou sadu souborů. Rozdělením tabulky date zabráníte konfliktu. Proto dělení tabulky podle podmínek běžně používaných v příkazu může významně snížit konflikty. Dělení tabulky podle sloupce s vysokou kardinalitou ale může vést k jiným problémům s výkonem kvůli velkému počtu podadresářů.

Výjimky při konfliktech

Pokud dojde ke konfliktu transakcí, zobrazí se některá z následujících výjimek:

Výjimka při souběžném připojování

Tato výjimka nastane, když souběžná operace přidá soubory ve stejném oddílu (nebo kdekoli v tabulce bez oddílů), který vaše operace přečte. Doplňky souborů můžou být způsobeny operacemi INSERT, DELETE, UPDATE, nebo MERGE operacemi.

S výchozí úrovní izolaceWriteSerializable, soubory přidané slepými operacemi (tj. operacemi, které slepě připojují data bez čtení jakýchkoli dat) nejsou v konfliktu s žádnou jinou operací, a to ani když se dotýkají stejné části (nebo kdekoli v nedělené tabulce). Pokud je úroveň izolace nastavená na Serializable, může dojít ke konfliktu slepých přírůstků.

Důležité: Nevidomá připojení mohou způsobovat konflikty v režimu WriteSerializable, pokud se více souběžných transakcí spouštějících DELETE, UPDATEnebo MERGE operace může odkazovat na hodnoty vložené nevidomými připojeními. Pokud se chcete tomuto konfliktu vyhnout, udělejte jednu z těchto věcí:

  • Ujistěte se, že souběžné operace DELETE, UPDATEnebo MERGE nepřečtou připojená data.
  • Mít maximálně jednu DELETE, UPDATEnebo MERGE operaci, která může číst připojená data.

Tato výjimka se často vyvolá během souběžných operací DELETE, UPDATE nebo MERGE. Zatímco souběžné operace můžou fyzicky aktualizovat různé adresáře diskových oddílů, jeden z nich může číst stejný oddíl, na nějž druhý souběžně aktualizuje, což způsobí konflikt. Tomu se můžete vyhnout tak, že oddělení v provozní podmínce explicitně uděláte. Představte si následující příklad.

// 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()

Předpokládejme, že výše uvedený kód spouštíte souběžně pro různá data nebo země. Vzhledem k tomu, že každá úloha pracuje na nezávislém oddílu v cílové tabulce Delta, neočekáváte žádné konflikty. Podmínka však není dostatečně explicitní a může prohledávat celou tabulku a může být v konfliktu se souběžnými operacemi, které aktualizují všechny ostatní oddíly. Místo toho můžete příkaz přepsat tak, aby do podmínky sloučení přidal konkrétní datum a zemi, jak je znázorněno v následujícím příkladu.

// 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()

Tato operace je teď bezpečná pro souběžné spuštění v různých datech a zemích.

ConcurrentDeleteReadException

K této výjimce dochází, když souběžná operace odstranila soubor, který operace přečetla. Mezi běžné příčiny patří operace DELETE, UPDATE, nebo operace MERGE, která přepisuje soubory.

ConcurrentDeleteDeleteException

K této výjimce dochází, když souběžná operace odstranila také soubor, který vaše operace odstraní. Příčinou můžou být dvě souběžné operace komprimace, které přepisují stejné soubory.

MetadataChangedException

K této výjimce dochází, když souběžná transakce aktualizuje metadata tabulky Delta. Běžné příčiny jsou ALTER TABLE operace nebo zápisy do tabulky Delta, které aktualizují schéma tabulky.

VýjimkaSoučasnýchTransakcí

Pokud se dotaz streamování používající stejné umístění kontrolního bodu spustí vícekrát současně a pokusí se najednou zapisovat do tabulky Delta. Nikdy byste neměli mít dva dotazy streamování, které používají stejné umístění kontrolního bodu a spouští se současně.

VýjimkaZměnaProtokolu

K této výjimce může dojít v následujících případech:

  • Při upgradu tabulky Delta na novou verzi protokolu. Aby budoucí operace mohly proběhnout úspěšně, možná budete muset upgradovat databricks Runtime.
  • Když více autorů vytváří nebo nahrazuje tabulku současně.
  • Když více autorů píše současně do prázdné cesty.

Další podrobnosti najdete v tématu Kompatibilita funkcí Delta Lake a protokoly .

Chování souběžnosti na úrovni řádků (starší verze)

Tato část popisuje chování verze Preview pro souběžnost na úrovni řádků v Databricks Runtime 14.1 a níže. Řádková souběžnost vždy vyžaduje vektory odstranění.

V Databricks Runtime 13.3 LTS a vyšší, tabulky s povoleným liquid clusteringem automaticky umožňují souběžnost na úrovni řádků.

V Databricks Runtime 14.0 a 14.1 můžete povolit souběžnost na úrovni řádků pro tabulky s vektory odstranění nastavením následující konfigurace pro cluster nebo SparkSession:

spark.databricks.delta.rowLevelConcurrencyPreview = true

Ve službě Databricks Runtime 14.1 a nižší, výpočet bez photonu podporuje pouze souběžnost na úrovni řádků pro DELETE operace.