การควบคุมการทํางานพร้อมกันสําหรับตารางเดลต้า

เมื่อสมุดบันทึก ไปป์ไลน์ หรืองาน Spark ของ Fabric หลายรายการเขียนลงในตารางเดลต้าเดียวกันในเวลาเดียวกัน Delta Lake จะใช้การควบคุมการทํางานพร้อมกันในแง่ดี (OCC) เพื่อให้ตารางสอดคล้องกัน แต่ละธุรกรรมจะอ่านสแนปช็อต เขียนไฟล์ใหม่ จากนั้นตรวจสอบว่าไม่มีการคอมมิตที่ขัดแย้งกันเกิดขึ้นระหว่างนั้น หากตรวจพบความขัดแย้ง ธุรกรรมจะล้มเหลวโดยมีข้อยกเว้นแทนที่จะทําให้ข้อมูลเสียหาย

บทความนี้ครอบคลุมรูปแบบที่ใช้งานได้จริงสําหรับการจัดการการเขียนพร้อมกันใน Fabric สําหรับข้อมูลจําเพาะทั้งหมดของโปรโตคอล OCC โปรดดู การควบคุมการทํางานพร้อมกันของ Delta Lake (เอกสารโอเพนซอร์ส)

ระดับการแยก

ตารางเดลต้าทั้งหมดใช้ระดับการแยกแบบอนุกรมได้ Serializable เป็นระดับที่เข้มงวดที่สุดและเป็นระดับเดียวที่รองรับ ช่วยให้มั่นใจได้ว่าผลลัพธ์ของธุรกรรมที่เกิดขึ้นพร้อมกันจะเหมือนกับคําสั่งดําเนินการตามลําดับ

Delta Lake ยังใช้ระดับ SnapshotIsolation ภายในสําหรับการดําเนินการที่ไม่เปลี่ยนแปลงข้อมูลเชิงตรรกะ (เช่น OPTIMIZE) SnapshotIsolation ข้ามการตรวจสอบการผนวกพร้อมกัน ซึ่งช่วยให้การบดอัดดําเนินการได้โดยไม่ขัดแย้งกับการแทรกพร้อมกัน คุณไม่ได้กําหนดค่า SnapshotIsolation โดยตรง แต่ Delta Lake จะนําไปใช้โดยอัตโนมัติตามความเหมาะสม

ด้วยการ Serializable แยก การผนวกแบบตาบอด (INSERT INTO) พร้อมกันอาจ ขัดแย้งกับ a MERGE หรือ UPDATE ที่อ่านพาร์ติชันเดียวกัน

การดําเนินการใดที่ขัดแย้งกัน

ไม่ใช่ว่าการเขียนพร้อมกันทั้งหมดจะขัดแย้งกัน ปัจจัยสําคัญคือการดําเนินการสองรายการสัมผัสกับไฟล์พื้นฐานเดียวกันหรือไม่

คู่พร้อมกัน ความขัดแย้ง? ทําไม
การดําเนินการ (ผนวก) สอง INSERT รายการ ไม่ใช่ แต่ละไฟล์จะเพิ่มไฟล์ใหม่โดยไม่ต้องอ่านไฟล์ที่มีอยู่ (ผนวกแบบตาบอด)
INSERT + OPTIMIZE ไม่ใช่ OPTIMIZE commits at SnapshotIsolation เนื่องจากไม่เปลี่ยนข้อมูลเชิงตรรกะ ดังนั้นจึงข้ามการตรวจสอบการผนวกพร้อมกันทั้งหมด ผนวก เพิ่มไฟล์ใหม่ที่ไม่ทับซ้อนกับไฟล์ที่กําลังกระชับ
สอง UPDATE, DELETEหรือ MERGE การดําเนินการ ใช่ หากพวกเขาอ่านหรือแก้ไขไฟล์ที่ทับซ้อนกัน แต่ละคนเขียนไฟล์ใหม่ ดังนั้นสแนปช็อตของผู้เขียนคนที่สองจึงค้าง
OPTIMIZE + UPDATE/DELETE/MERGE ใช่ ถ้าพวกเขาสัมผัสไฟล์เดียวกัน OPTIMIZE ลบและอ่านไฟล์ (ด้วย dataChange=false) หากการดําเนินการแก้ไขข้อมูลอ่านไฟล์ ConcurrentDeleteReadException เดียวกันด้วย
สอง OPTIMIZE รัน ใช่ หากพวกเขาเลือกไฟล์เดียวกัน ทั้งสองพยายามลบและเขียนไฟล์ชุดเดียวกันใหม่ทริกเกอร์ ConcurrentDeleteDeleteExceptionไฟล์
INSERT + MERGE/UPDATE/DELETE ใช่ หากการดําเนินการแก้ไขข้อมูลอ่านพาร์ติชันเดียวกัน ภายใต้ Serializableการผนวกแบบตาบอดอาจขัดแย้งกับการแก้ไขข้อมูลพร้อมกันหากการดําเนินการอ่านพาร์ติชันที่ผนวกเขียนไป

เคล็ดลับ

ไปป์ไลน์แบบผนวกอย่างเดียว (INSERT INTO, ) df.write.mode("append")เป็นวิธีที่ง่ายที่สุดในการหลีกเลี่ยงความขัดแย้งโดยสิ้นเชิง หากปริมาณงานของคุณสามารถผนวกก่อนและกระทบยอดในภายหลัง คุณจะขจัดความขัดแย้งในการเขียน-เขียน

แยกนักเขียนด้วยการแบ่งพาร์ติชัน

วิธีที่พบบ่อยที่สุดในการเรียกใช้ DML พร้อมกันกับตารางเดียวกันโดยไม่มีข้อขัดแย้งคือการ แบ่งพาร์ติชันตาราง ตามคอลัมน์ที่แยกผู้เขียนของคุณจากนั้นรวมคอลัมน์นั้นในทุกเงื่อนไขการทํางาน เมื่อผู้เขียนแต่ละคนกําหนดเป้าหมายพาร์ติชันที่แตกต่างกันการดําเนินการจะสัมผัสกับชุดไฟล์ที่ไม่ต่อเนื่องและไม่ขัดแย้งกัน

สถานการณ์ทั่วไป: ไปป์ไลน์หลายรายการแต่ละกระบวนการข้อมูลสําหรับหน่วยธุรกิจหรือผู้เช่าที่แตกต่างกัน แบ่งพาร์ติชันตามมิตินั้นและปักหมุดแต่ละไปป์ไลน์ MERGE เข้ากับพาร์ติชัน

-- Each pipeline targets its own partition, so concurrent runs don't conflict
MERGE INTO events AS target
USING staged AS source
ON target.event_id = source.event_id
    AND target.business_unit = 'EMEA'
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *

สำคัญ

คอลัมน์พาร์ติชันต้องปรากฏในเงื่อนไขการผสานเอง ไม่ใช่แค่ในข้อมูลต้นฉบับเท่านั้น หากไม่มี Delta Lake จะไม่สามารถระบุได้ในเวลาตรวจสอบความถูกต้องว่าการดําเนินการทั้งสองสัมผัสกับชุดไฟล์ที่ไม่ต่อเนื่องกัน และตัวตรวจสอบข้อขัดแย้งจะถือว่าการดําเนินการเป็นการอ่านแบบเต็มตาราง

สําหรับรายละเอียดเพิ่มเติมเกี่ยวกับกลยุทธ์การแบ่งพาร์ติชัน โปรดดู การแบ่งพาร์ติชันสําหรับตารางเดลต้า

การลองคอมมิตใหม่ในตัว

Delta Lake ลองคอมมิตใหม่โดยอัตโนมัติเมื่อตรวจพบว่าธุรกรรมอื่นถูกส่งไปก่อน ในการลองใหม่แต่ละครั้ง จะอ่านคอมมิตที่ชนะ รันตัวตรวจสอบความขัดแย้ง และหากไม่มีข้อขัดแย้งเชิงตรรกะ จะพยายามคอมมิตอีกครั้งในเวอร์ชันถัดไปที่พร้อมใช้งาน กระบวนการนี้ทําซ้ําอย่างโปร่งใสโดยไม่ต้องดําเนินการใดๆ จากโค้ดของคุณ

ความขัดแย้งเชิงตรรกะ (ตัวอย่างเช่น การดําเนินการสองรายการที่เขียนแฟ้มเดียวกันใหม่) จะไม่สามารถแก้ไขได้โดยอัตโนมัติ การลองใหม่จะทําให้เกิดข้อยกเว้นข้อใดข้อหนึ่งที่ระบุไว้ในข้อยกเว้นความขัดแย้งทั่วไป อย่างไรก็ตาม การชนกันของเวอร์ชันชั่วคราวจํานวนมาก เช่น การต่อท้ายแบบตาบอดสองช่องที่แข่งขันกันในช่องเวอร์ชันเดียวกัน จะได้รับการแก้ไขโดยอัตโนมัติและจะไม่ปรากฏในแอปพลิเคชันของคุณ

ข้อยกเว้นความขัดแย้งทั่วไป

เมื่อตรวจพบความขัดแย้ง Delta Lake จะยกข้อยกเว้นเฉพาะ การทําความเข้าใจข้อยกเว้นที่คุณเห็นจะช่วยระบุสาเหตุที่แท้จริง

ข้อยกเว้น เกิดอะไรขึ้น
ConcurrentAppendException นักเขียนคนอื่นผนวกไฟล์ในพาร์ติชัน (หรือชุดไฟล์) ที่การดําเนินการของคุณกําลังอ่าน พบได้บ่อยเมื่อ a MERGE วิ่งกับพาร์ติชันที่รับการแทรกจากไปป์ไลน์อื่นด้วย ภายใต้ Serializable การแยก แม้แต่ส่วนต่อท้ายแบบตาบอด (การดําเนินการธรรมดา INSERT ) ก็สามารถเรียกใช้ข้อยกเว้นนี้ได้
ConcurrentDeleteReadException นักเขียนคนอื่นลบหรือเขียนไฟล์ใหม่ที่การดําเนินการของคุณอ่าน โดยทั่วไปเมื่อ OPTIMIZE กระชับไฟล์ที่ UPDATE กําลังอ่านพร้อมกันหรือ MERGE กําลังอ่านอยู่ หรือเมื่อการดําเนินการแก้ไขข้อมูลสองรายการทับซ้อนกันในแถวเดียวกัน
ConcurrentDeleteDeleteException การดําเนินการทั้งสองพยายามลบหรือเขียนไฟล์เดียวกันใหม่ มักเกิดจากการรันที่ OPTIMIZE ทับซ้อนกันหรือสองไปป์ไลน์เขียนพาร์ติชันเดียวกันใหม่พร้อมกัน
ConcurrentWriteException ข้อขัดแย้งทั่วไปที่เกิดขึ้นเมื่อธุรกรรมอื่นที่ผูกมัดกับเวอร์ชันตารางเดียวกันก่อนที่การแก้ไขข้อขัดแย้งจะสามารถเรียกใช้ได้ เช่น ในระหว่างการอัปเกรดระบบไฟล์เพื่อจัดการ
MetadataChangedException สคีมาตารางหรือคุณสมบัติเปลี่ยนไประหว่างธุรกรรม ตัวอย่างเช่น การเขียนวิวัฒนาการแบบพร้อมกัน ALTER TABLE หรือสคีมา
ConcurrentTransactionException การสืบค้นการสตรีมที่มีโครงสร้างสองรายการที่มีตําแหน่งจุดตรวจสอบเดียวกันเขียนลงในตารางในเวลาเดียวกัน ขจัดงานสตรีมมิ่งของคุณซ้ําซ้อนหรือใช้เส้นทางจุดตรวจที่แตกต่างกัน
ProtocolChangedException ธุรกรรมที่เกิดขึ้นพร้อมกันได้อัปเกรดหรือดาวน์เกรดโปรโตคอลตารางในขณะที่ธุรกรรมปัจจุบันกําลังพยายามเปลี่ยนแปลงโปรโตคอลด้วย นอกจากนี้ยังสามารถเกิดขึ้นได้เมื่อคุณลักษณะตารางถูกทิ้งพร้อมกัน

กลยุทธ์ทั่วไปเพื่อหลีกเลี่ยงความขัดแย้งในการเขียน

เปิดใช้งานการบดอัดอัตโนมัติ

การบดอัดอัตโนมัติ ทํางานแบบซิงโครนัสเป็นส่วนหนึ่งของการดําเนินการเขียน การบดอัดแบบซิงโครนัสป้องกันไม่ให้งานการบดอัดตามกําหนดการแยกต่างหากทับซ้อนกับการดําเนินการแก้ไขข้อมูล และทําให้เกิดข้อยกเว้นของผู้เขียนพร้อมกัน

กําหนดการบํารุงรักษานอกหน้าต่างการเขียน

OPTIMIZE และ VACUUM อาจขัดแย้งกับการดําเนินการแก้ไขข้อมูลพร้อมกัน ใน Fabric ให้จัดกําหนดการงานสมุดบันทึกหรือกิจกรรมไปป์ไลน์สําหรับ table compaction และ VACUUM ในช่วงที่มีกิจกรรมต่ํา เช่น หลังจากการนําเข้าทุกคืนเสร็จสิ้นแทนที่จะเป็นในระหว่างนั้น

ใช้รูปแบบผนวก + ผสาน

สําหรับการนําเข้าพร้อมกันสูง ให้ลงจอดข้อมูลดิบด้วยการเขียนแบบผนวกอย่างเดียวลงในตารางการจัดเตรียม (ไม่มีข้อขัดแย้ง) จากนั้นเรียกใช้งานเดียว MERGE เพื่อกระทบยอดลงในตารางเป้าหมาย รูปแบบนี้ทําให้การดําเนินการที่เสี่ยงต่อความขัดแย้งเป็นอนุกรมในขณะที่รักษาการนําเข้าให้ขนานกันอย่างสมบูรณ์

เพิ่มตรรกะการลองใหม่สําหรับข้อขัดแย้งเชิงตรรกะ

การลองคอมมิตใหม่ในตัวจะจัดการกับการชนกันของเวอร์ชันชั่วคราวโดยอัตโนมัติ แต่ความขัดแย้งเชิงตรรกะ ซึ่งการดําเนินการสองรายการทับซ้อนกันอย่างแท้จริงทําให้เกิดข้อยกเว้น เนื่องจาก Delta Lake ไม่เคยสร้างการเขียนบางส่วน ธุรกรรมที่ล้มเหลวจึงปลอดภัยที่จะลองใหม่ในระดับแอปพลิเคชัน สําหรับไปป์ไลน์ที่คาดว่าจะมีข้อขัดแย้งทางตรรกะเป็นครั้งคราว ให้ตัดตรรกะการเขียนในการลองใหม่:

from delta.exceptions import ConcurrentAppendException
import time

# Retry with backoff on transient concurrent write conflicts
max_retries = 3
for attempt in range(max_retries):
    try:
        spark.sql("MERGE INTO target USING source ON ...")
        break
    except ConcurrentAppendException:
        if attempt < max_retries - 1:
            time.sleep(2 ** attempt)
        else:
            raise

เลือกกลยุทธ์เลย์เอาต์ที่เหมาะสม

การจัดกลุ่มและการแบ่งพาร์ติชันของเหลวช่วยแก้ปัญหาต่างๆ การจัดกลุ่ม Liquid ปรับเค้าโครงไฟล์ให้เหมาะสมเพื่อประสิทธิภาพการอ่าน การแบ่งพาร์ติชันสร้างขอบเขตทางกายภาพที่ป้องกันความขัดแย้งของผู้เขียนพร้อมกัน หากปริมาณงานของคุณต้องการทั้งสองอย่าง ให้แบ่งพาร์ติชันตามคอลัมน์การแยกตัวเขียนและใช้ Z-Order ภายในแต่ละพาร์ติชันเพื่อประสิทธิภาพการอ่าน