Ú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í na úrovni izolace.
Delta Lake poskytuje záruky transakcí ACID mezi čtením a zápisem. To znamená, že:
- Oddíl tabulky může současně upravovat více zapisovačů ve více clusterech. Zapisovače vidí konzistentní zobrazení snímků tabulky a zápisů 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.
Čtení streamování 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 s 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 dělení
- Tabulky s clusteringem liquid, pokud jste nezablokovali vektory 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ů.
Další verze Modulu runtime Databricks najdete v tématu Chování souběžnosti na úrovni řádků (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) | AKTUALIZOVAT, ODSTRANIT, SLOUČIT DO | OPTIMIZE | |
---|---|---|---|
INSERT | Nejde v konfliktu | ||
AKTUALIZOVAT, ODSTRANIT, SLOUČIT DO | Nelze konfliktovat v writeSerializable. Při úpravě stejného řádku může dojít ke konfliktu v serializovatelném systému. 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 | Nejde v konfliktu | Může dojít ke konfliktu při ZORDER BY použití. Jinak nelze konfliktovat. |
Může dojít ke konfliktu při ZORDER BY použití. Jinak nelze konfliktovat. |
Důležité
(1) Všechny INSERT
operace v tabulkách výše popisují operace připojení, které před potvrzením nepřečtou žádná data ze stejné tabulky. 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
upgrade, protokoly tabulek se změní, což je v konfliktu se všemi probíhajícími operacemi.
Konflikty zápisu bez souběžnosti 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) | AKTUALIZOVAT, ODSTRANIT, SLOUČIT DO | OPTIMIZE | |
---|---|---|---|
INSERT | Nejde v konfliktu | ||
AKTUALIZOVAT, ODSTRANIT, SLOUČIT DO | Nelze konfliktovat v writeSerializable. Může být v konfliktu v Serializovatelné. Podívejte se, jak se vyhnout konfliktům s oddíly. | Může kolidovat v Serializovatelné a WriteSerializable. Podívejte se, jak se vyhnout konfliktům s oddíly. | |
OPTIMIZE | Nejde v konfliktu | Nelze v konfliktu s tabulkami s povolenými vektory odstranění, pokud ZORDER BY se nepoužívá. Může být v konfliktu jinak. |
Nelze v konfliktu s tabulkami s povolenými vektory odstranění, pokud ZORDER BY se nepoužívá. Může být v konfliktu jinak. |
Důležité
(1) Všechny INSERT
operace v tabulkách výše popisují operace připojení, které před potvrzením nepřečtou žádná data ze stejné tabulky. 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
upgrade, protokoly tabulek se změní, což je v konfliktu se všemi probíhajícími operacemi.
Omezení souběžnosti na úrovni řádků
Některá omezení platí pro souběžnost na úrovni řádků. Pro následující operace se řešení konfliktů řídí normální souběžností 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ři řešení konfliktů a může dojít ke konfliktům.
Platí také všechna omezení pro vektory odstranění. Viz Omezení.
Kdy se Delta Lake potvrdí bez čtení tabulky?
Operace Delta Lake INSERT
nebo připojení před potvrzením nečtou stav tabulky, pokud jsou splněny následující podmínky:
- Logika se vyjadřuje pomocí
INSERT
logiky SQL nebo režimu připojení. - Logika neobsahuje žádné poddotazy ani podmíněné výrazy, které odkazují na tabulku cílenou operací zápisu.
Stejně jako v jiných potvrzeních Delta Lake ověřuje a překládá verze tabulek při potvrzení pomocí metadat v transakčním protokolu, ale ve skutečnosti se nečte žádná verze tabulky.
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: Serializovatelné 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 čtenář může zobrazit snímek tabulky, že 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, dlouhotrvající odstranění a txn2, které vkládá data odstraněná pomocí txn1. txn2 a txn1 jsou dokončeny a jsou zaznamenány v daném 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í WriteSerializable
Serializable
na , 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:
ConcurrentAppendException
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í WriteSerializable
izolace souborů přidaných nevidomými INSERT
operacemi (to znamená operace, které slepě připojují data bez čtení dat) nejsou v konfliktu s žádnou operací, i když se dotknou stejného oddílu (nebo kdekoli v tabulce bez dělení). Pokud je úroveň izolace nastavená na , může dojít ke Serializable
konfliktu slepých připojení.
Tato výjimka se často vyvolá během souběžných DELETE
UPDATE
operací nebo MERGE
operací. Zatímco souběžné operace můžou fyzicky aktualizovat různé adresáře oddílů, jeden z nich může číst stejný oddíl, který se 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ří DELETE
operace UPDATE
, nebo MERGE
operace, 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.
ConcurrentTransactionException
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ě.
ProtocolChangedException
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 zapisovačů vytváří nebo nahrazuje tabulku najednou.
- Když více zapisovačů současně zapisuje do prázdné cesty.
Další podrobnosti najdete v tématu Jak Azure Databricks spravuje kompatibilitu funkcí Delta Lake?
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. Souběžnost na úrovni řádků vždy vyžaduje vektory odstranění.
V Databricks Runtime 13.3 LTS a novějších tabulkách s povoleným clusteringem liquid umožňují automaticky 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 novějších výpočetních funkcích bez photonu podporuje pouze souběžnost na úrovni řádků pro DELETE
operace.