Bagikan melalui


Tingkat isolasi dan konflik penulisan di Azure Databricks

Tingkat isolasi tabel menentukan sejauh mana transaksi harus diisolasi dari modifikasi yang dilakukan oleh operasi bersamaan. Menulis konflik di Azure Databricks bergantung pada tingkat isolasi.

Delta Lake memberikan jaminan transaksi ACID antara membaca dan menulis. Ini berarti bahwa:

  • Beberapa penulis di beberapa kluster dapat secara bersamaan memodifikasi partisi tabel. Penulis melihat tampilan rekam jepret tabel yang konsisten dan penulisan terjadi dalam urutan serial.
    • Pembaca terus melihat tampilan snapshot yang konsisten dari tabel yang dimulai dengan pekerjaan Azure Databricks, bahkan ketika tabel dimodifikasi selama pekerjaan.

Lihat Apa itu jaminan ACID di Azure Databricks?.

Catatan

Azure Databricks menggunakan Delta Lake untuk semua tabel secara default. Artikel ini menjelaskan perilaku untuk Delta Lake di Azure Databricks.

Penting

Perubahan metadata menyebabkan semua operasi tulis bersamaan gagal. Operasi ini mencakup perubahan pada protokol tabel, properti tabel, atau skema data.

Pembacaan streaming gagal saat mengalami penerapan yang mengubah metadata tabel. Jika Anda ingin aliran berlanjut, Anda harus memulai ulang. Untuk metode yang direkomendasikan, lihat Pertimbangan produksi untuk Streaming Terstruktur.

Berikut ini adalah contoh kueri yang mengubah 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);

Menulis konflik dengan konkurensi tingkat baris

Konkurensi tingkat baris mengurangi konflik antara operasi tulis bersamaan dengan mendeteksi perubahan di tingkat baris dan secara otomatis menyelesaikan konflik yang terjadi saat penulisan bersamaan memperbarui atau menghapus baris yang berbeda dalam file data yang sama.

Konkurensi tingkat baris umumnya tersedia pada Databricks Runtime 14.2 ke atas. Konkurensi tingkat baris didukung secara default untuk kondisi berikut:

  • Tabel dengan vektor penghapusan diaktifkan dan tanpa partisi.
  • Tabel dengan pengklusteran cair, kecuali Anda telah menonaktifkan vektor penghapusan.

Tabel dengan partisi tidak mendukung konkurensi tingkat baris tetapi masih dapat menghindari konflik antara OPTIMIZE dan semua operasi tulis lainnya saat vektor penghapusan diaktifkan. Lihat Batasan untuk konkurensi tingkat baris.

Untuk versi Runtime Databricks lainnya, lihat Perilaku pratinjau konkurensi tingkat baris (warisan).

MERGE INTO dukungan untuk konkurensi tingkat baris memerlukan Photon di Databricks Runtime 14.2. Dalam Databricks Runtime 14.3 LTS ke atas, Photon tidak diperlukan.

Tabel berikut menjelaskan pasangan operasi tulis mana yang dapat berkonflik di setiap tingkat isolasi dengan konkurensi tingkat baris diaktifkan.

Catatan

Tabel dengan kolom identitas tidak mendukung transaksi bersamaan. Lihat Menggunakan kolom identitas di Delta Lake.

SISIPKAN (1) PERBARUI, HAPUS, GABUNGKAN MENJADI OPTIMIZE
INSERT Tidak bisa berkonflik
PERBARUI, HAPUS, GABUNGKAN MENJADI Tidak dapat berkonflik dalam WriteSerializable. Dapat berkonflik di Serializable saat memodifikasi baris yang sama. Lihat Batasan untuk konkurensi tingkat baris. Dapat berkonflik saat mengubah baris yang sama. Lihat Batasan untuk konkurensi tingkat baris.
OPTIMIZE Tidak bisa berkonflik Dapat berkonflik saat ZORDER BY digunakan. Tidak dapat berkonflik jika tidak. Dapat berkonflik saat ZORDER BY digunakan. Tidak dapat berkonflik jika tidak.

Penting

(1) Semua INSERT operasi dalam tabel di atas menjelaskan operasi penambahan yang tidak membaca data apa pun dari tabel yang sama sebelum melakukan. INSERT operasi yang berisi subkueri yang membaca tabel yang sama mendukung konkurensi yang sama dengan MERGE.

Menulis konflik tanpa konkurensi tingkat baris

Tabel berikut menjelaskan pasangan operasi tulis mana yang dapat bertentangan di setiap tingkat isolasi.

Tabel tidak mendukung konkurensi tingkat baris jika memiliki partisi yang ditentukan atau tidak mengaktifkan vektor penghapusan. Databricks Runtime 14.2 atau lebih tinggi diperlukan untuk konkurensi tingkat baris.

Catatan

Tabel dengan kolom identitas tidak mendukung transaksi bersamaan. Lihat Menggunakan kolom identitas di Delta Lake.

SISIPKAN (1) PERBARUI, HAPUS, GABUNGKAN MENJADI OPTIMIZE
INSERT Tidak bisa berkonflik
PERBARUI, HAPUS, GABUNGKAN MENJADI Tidak dapat berkonflik dalam WriteSerializable. Dapat berkonflik dalam Serializable. Lihat menghindari konflik dengan partisi. Dapat berkonflik dalam Serializable dan WriteSerializable. Lihat menghindari konflik dengan partisi.
OPTIMIZE Tidak bisa berkonflik Tidak dapat bertentangan dengan dalam tabel dengan vektor penghapusan diaktifkan, kecuali ZORDER BY digunakan. Dapat berkonflik jika tidak. Tidak dapat bertentangan dengan dalam tabel dengan vektor penghapusan diaktifkan, kecuali ZORDER BY digunakan. Dapat berkonflik jika tidak.

Penting

(1) Semua INSERT operasi dalam tabel di atas menjelaskan operasi penambahan yang tidak membaca data apa pun dari tabel yang sama sebelum melakukan. INSERT operasi yang berisi subkueri yang membaca tabel yang sama mendukung konkurensi yang sama dengan MERGE.

Batasan untuk konkurensi tingkat baris

Beberapa batasan berlaku untuk konkurensi tingkat baris. Untuk operasi berikut, resolusi konflik mengikuti konkurensi normal untuk konflik tulis di Azure Databricks. Lihat Menulis konflik tanpa konkurensi tingkat baris.

  • Perintah dengan klausa kondisional yang kompleks, termasuk yang berikut ini:
    • Kondisi pada jenis data kompleks seperti struktur, array, atau peta.
    • Kondisi menggunakan ekspresi dan subkueri non-deterministik.
    • Kondisi yang berisi subkueri berkorelasi.
  • Untuk MERGE perintah, Anda harus menggunakan predikat eksplisit pada tabel target untuk memfilter baris yang cocok dengan tabel sumber. Untuk resolusi penggabungan, filter digunakan untuk hanya memindai baris yang mungkin bertentangan berdasarkan kondisi filter dalam operasi bersamaan.

Catatan

Deteksi konflik tingkat baris dapat meningkatkan total waktu eksekusi. Dalam kasus banyak transaksi bersamaan, penulis memprioritaskan latensi atas penyelesaian konflik dan konflik dapat terjadi.

Semua batasan untuk vektor penghapusan juga berlaku. Lihat Batasan.

Kapan Delta Lake berkomitmen tanpa membaca tabel?

Delta Lake INSERT atau operasi tambahan tidak membaca status tabel sebelum melakukan jika kondisi berikut ini terpenuhi:

  1. Logika diekspresikan menggunakan INSERT logika SQL atau mode tambahan.
  2. Logika tidak berisi subkueri atau kondisi yang mereferensikan tabel yang ditargetkan oleh operasi tulis.

Seperti dalam penerapan lain, Delta Lake memvalidasi dan menyelesaikan versi tabel pada penerapan menggunakan metadata dalam log transaksi, tetapi tidak ada versi tabel yang benar-benar dibaca.

Catatan

Banyak pola umum menggunakan MERGE operasi untuk menyisipkan data berdasarkan kondisi tabel. Meskipun mungkin untuk menulis ulang logika ini menggunakan INSERT pernyataan, jika ada ekspresi kondisional yang mereferensikan kolom dalam tabel target, pernyataan ini memiliki batasan konkurensi yang sama dengan MERGE.

Menulis tingkat isolasi yang dapat diserialisasi vs. yang dapat diserialisasi

Tingkat isolasi tabel menentukan sejauh mana transaksi harus diisolasi dari modifikasi yang dilakukan oleh transaksi bersamaan. Delta Lake di Azure Databricks mendukung dua tingkat isolasi: Serializable dan WriteSerializable.

  • Serializable: Tingkat isolasi terkuat. Ini memastikan bahwa operasi tulis yang berkomitmen dan semua bacaan adalah Serializable. Operasi diperbolehkan selama ada urutan serial mengeksekusinya satu per satu yang menghasilkan hasil yang sama seperti yang terlihat dalam tabel. Untuk operasi tulis, urutan serial persis sama dengan yang terlihat dalam riwayat tabel.

  • WriteSerializable (Default): Tingkat isolasi yang lebih lemah daripada Serializable. Ini memastikan hanya bahwa operasi tulis (yaitu, bukan bacaan) adalah serializable. Namun, ini masih lebih kuat dari isolasi Snapshot. WriteSerializable adalah tingkat isolasi default karena memberikan keseimbangan yang sangat baik antara konsistensi data dan ketersediaan untuk operasi yang paling umum.

    Dalam mode ini, konten tabel Delta mungkin berbeda dari yang diharapkan dari urutan operasi yang terlihat dalam riwayat tabel. Hal ini dikarenakan mode ini memungkinkan pasangan tertentu dari tulisan bersamaan (misal, operasi X dan Y) untuk melanjutkan sedemikian rupa sehingga hasilnya akan seolah-olah Y dilakukan sebelum X (yaitu, serializable di antara mereka) meskipun riwayat akan menunjukkan bahwa Y dilakukan setelah X. Untuk melarang pemesanan ulang ini, atur tingkat isolasi tabel menjadi Serializable agar transaksi ini gagal.

Operasi baca selalu menggunakan isolasi snapshot. Tingkat isolasi tulis menentukan apakah mungkin bagi pembaca untuk melihat snapshot tabel, yang menurut riwayat, "tidak pernah ada".

Untuk tingkat Serializable, pembaca selalu melihat hanya tabel yang sesuai dengan riwayat. Untuk tingkat WriteSerializable, pembaca dapat melihat tabel yang tidak ada di log Delta.

Misalnya, pertimbangkan txn1, penghapusan dan txn2 yang sudah berjalan lama, yang menyisipkan data yang dihapus oleh txn1. txn2 dan txn1 lengkap dan tercatat dalam urutan itu di riwayat. Menurut riwayat, data yang dimasukkan dalam txn2 seharusnya tidak ada dalam tabel. Untuk tingkat Serializable, pembaca tidak akan pernah melihat data yang dimasukkan oleh txn2. Namun, untuk tingkat WriteSerializable, pembaca bisa di beberapa titik melihat data yang dimasukkan oleh txn2.

Untuk informasi selengkapnya tentang jenis operasi mana yang dapat bertentangan satu sama lain di setiap tingkat isolasi dan kemungkinan kesalahan, lihat Menghindari konflik menggunakan kondisi perintah pemartisian dan terpisah.

Atur tingkat isolasi

Anda mengatur tingkat isolasi menggunakan perintah ALTER TABLE.

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

di mana <level-name> adalah Serializable atau WriteSerializable.

Misalnya, untuk mengubah tingkat isolasi dari WriteSerializable default ke Serializable, jalankan:

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

Hindari konflik menggunakan kondisi perintah partisi dan putus-putus

Dalam semua kasus ditandai "dapat konflik", apakah kedua operasi akan bertentangan tergantung pada apakah mereka beroperasi pada set file yang sama. Anda dapat membuat dua set file yang dipisahkan dengan mempartisi tabel dengan kolom yang sama dengan yang digunakan dalam kondisi operasi. Misalnya, dua perintah UPDATE table WHERE date > '2010-01-01' ... dan DELETE table WHERE date < '2010-01-01' akan bertentangan jika tabel tidak dipartisi berdasarkan tanggal, karena keduanya dapat mencoba memodifikasi kumpulan file yang sama. Mempartisi tabel dengan date akan menghindari konflik. Oleh karena itu, mempartisi tabel sesuai dengan kondisi yang umum digunakan pada perintah dapat mengurangi konflik secara signifikan. Namun, mempartisi tabel menurut kolom yang memiliki kardinalitas tinggi dapat menyebabkan masalah performa lainnya karena banyaknya subdirektori.

Pengecualian konflik

Saat terjadi konflik transaksi, Anda akan mengamati salah satu pengecualian berikut:

ConcurrentAppendException

Pengecualian ini terjadi ketika operasi bersamaan menambahkan file di partisi yang sama (atau di mana saja dalam tabel yang tidak dipartisi) yang dibaca oleh operasi Anda. Penambahan file dapat disebabkan oleh operasi INSERT, DELETE, UPDATE, atau MERGE.

Dengan tingkat isolasi default dari WriteSerializable, file yang ditambahkan oleh operasi butaINSERT (yaitu, operasi yang secara membabi buta menambahkan data tanpa membaca data apa pun) tidak bertentangan dengan operasi apa pun, bahkan jika mereka menyentuh partisi yang sama (atau di mana saja dalam tabel yang tidak dipartisi). Jika tingkat isolasi diatur ke Serializable, maka penambahan buta mungkin bertentangan.

Pengecualian ini sering dilemparkan selama bersamaan operasi DELETE, UPDATE, atau MERGE. Sementara operasi bersamaan mungkin secara fisik memperbarui direktori partisi yang berbeda, salah satu dari mereka dapat membaca partisi yang sama yang lain secara bersamaan memperbarui, sehingga menyebabkan konflik. Anda dapat menghindari hal ini dengan membuat pemisahan eksplisit dalam kondisi operasi. Pertimbangkan contoh berikut.

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

Misalkan Anda menjalankan kode di atas secara bersamaan untuk tanggal atau negara yang berbeda. Karena setiap pekerjaan bekerja pada partisi independen pada tabel Delta target, Anda tidak mengharapkan konflik apa pun. Namun, kondisinya tidak cukup eksplisit dan dapat memindai seluruh tabel dan dapat bertentangan dengan operasi bersamaan yang memperbarui partisi lainnya. Sebagai gantinya, Anda dapat menulis ulang pernyataan Anda untuk menambahkan tanggal dan negara tertentu ke kondisi gabungan, seperti yang ditunjukkan dalam contoh berikut.

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

Operasi ini sekarang aman untuk dijalankan secara bersamaan pada tanggal dan negara yang berbeda.

ConcurrentDeleteReadException

Pengecualian ini terjadi ketika operasi bersamaan menghapus file yang dibaca operasi Anda. Penyebab umum adalah operasi DELETE, UPDATE, atau MERGE yang menulis ulang file.

ConcurrentDeleteDeleteException

Pengecualian ini terjadi ketika operasi bersamaan menghapus file yang juga dihapus oleh operasi Anda. Ini bisa disebabkan oleh dua operasi pemadatan bersamaan yang menulis ulang file yang sama.

MetadataChangedException

Pengecualian ini terjadi ketika transaksi bersamaan memperbarui metadata tabel Delta. Penyebab umum adalah operasi ALTER TABLE atau penulisan ke tabel Delta Anda yang memperbarui skema tabel.

ConcurrentTransactionException

Jika kueri streaming menggunakan lokasi pos pemeriksaan yang sama dimulai beberapa kali secara bersamaan dan mencoba menulis ke tabel Delta secara bersamaan. Anda seharusnya tidak pernah memiliki dua kueri streaming menggunakan lokasi pos pemeriksaan yang sama dan berjalan pada saat yang bersamaan.

ProtocolChangedException

Pengecualian ini dapat terjadi dalam kasus-kasus berikut:

  • Saat tabel Delta Anda dimutakhirkan ke versi protokol baru. Agar operasi di masa mendatang berhasil, Anda mungkin perlu meningkatkan Runtime Databricks Anda.
  • Ketika beberapa penulis membuat atau mengganti tabel pada saat yang sama.
  • Ketika beberapa penulis menulis ke jalan kosong pada saat yang sama.

Lihat Bagaimana Azure Databricks mengelola kompatibilitas fitur Delta Lake? untuk detail selengkapnya.

Perilaku pratinjau konkurensi tingkat baris (warisan)

Bagian ini menjelaskan perilaku pratinjau untuk konkurensi tingkat baris di Databricks Runtime 14.1 ke bawah. Konkurensi tingkat baris selalu memerlukan vektor penghapusan.

Di Databricks Runtime 13.3 LTS ke atas, tabel dengan pengklusteran cair diaktifkan secara otomatis mengaktifkan konkurensi tingkat baris.

Di Databricks Runtime 14.0 dan 14.1, Anda dapat mengaktifkan konkurensi tingkat baris untuk tabel dengan vektor penghapusan dengan mengatur konfigurasi berikut untuk kluster atau SparkSession:

spark.databricks.delta.rowLevelConcurrencyPreview = true

Dalam Databricks Runtime 14.1 ke bawah, komputasi non-Photon hanya mendukung konkurensi tingkat baris untuk DELETE operasi.