Halaman ini menjelaskan transaksi di Spanner dan memperkenalkan antarmuka transaksi DML terpartisi, hanya baca, dan baca-tulis Spanner.
Transaksi di Spanner adalah serangkaian operasi baca dan tulis. Semua operasi dalam transaksi bersifat atomik, yang berarti semuanya berhasil atau semuanya gagal.
Sesi digunakan untuk melakukan transaksi di database Spanner. Sesi mewakili saluran komunikasi logis dengan layanan database Spanner. Sesi dapat menjalankan satu atau beberapa transaksi dalam satu waktu. Untuk mengetahui informasi selengkapnya, lihat Sesi.
Jenis transaksi
Spanner mendukung jenis transaksi berikut, yang masing-masing dirancang untuk pola interaksi data tertentu:
Baca-tulis: Transaksi ini digunakan untuk operasi baca dan tulis, diikuti dengan commit. Mereka mungkin memperoleh kunci. Jika gagal, tugas akan memerlukan percobaan ulang. Meskipun terbatas pada satu database, pengguna dapat mengubah data di beberapa tabel dalam database tersebut.
Hanya baca: Transaksi ini menjamin konsistensi data di beberapa operasi baca, tetapi tidak mengizinkan modifikasi data. Eksekusi dilakukan pada stempel waktu yang ditentukan sistem agar konsisten, atau pada stempel waktu sebelumnya yang dikonfigurasi pengguna. Tidak seperti transaksi baca-tulis, transaksi ini tidak memerlukan operasi atau kunci commit. Namun, operasi tersebut mungkin dijeda untuk menunggu operasi tulis yang sedang berlangsung selesai.
DML yang dipartisi: Jenis transaksi ini menjalankan pernyataan DML sebagai operasi DML yang dipartisi. Pernyataan ini dioptimalkan untuk menjalankan pernyataan DML dalam skala besar, tetapi dengan batasan untuk memastikan pernyataan bersifat idempoten dan dapat dipartisi dengan cara yang memungkinkan pernyataan tersebut dijalankan secara independen dari partisi lain. Untuk banyak penulisan yang tidak memerlukan transaksi atomik, pertimbangkan untuk menggunakan penulisan batch. Untuk mengetahui informasi selengkapnya, lihat Mengubah data menggunakan operasi tulis batch.
Transaksi baca-tulis
Transaksi baca-tulis terdiri dari nol atau lebih pernyataan baca atau kueri yang diikuti dengan permintaan penerapan. Kapan saja sebelum permintaan penerapan, klien dapat mengirim permintaan rollback untuk membatalkan transaksi.
Isolasi serialisabel
Dengan menggunakan tingkat isolasi serializable default, transaksi baca-tulis membaca, mengubah, dan menulis data secara atomik. Jenis transaksi ini konsisten secara eksternal.
Saat menggunakan transaksi baca-tulis, sebaiknya minimalkan waktu transaksi aktif. Durasi transaksi yang lebih pendek menyebabkan kunci dipegang dalam waktu yang lebih singkat, sehingga meningkatkan kemungkinan commit yang berhasil dan mengurangi pertentangan. Hal ini karena kunci yang dipegang lama dapat menyebabkan deadlock dan pembatalan transaksi. Spanner mencoba mempertahankan kunci baca tetap aktif selama transaksi terus melakukan pembacaan dan transaksi belum dihentikan melalui commit atau roll back. Jika klien tetap tidak aktif dalam jangka waktu yang lama, Spanner dapat melepaskan kunci transaksi dan membatalkan transaksi.
Untuk melakukan operasi tulis yang bergantung pada satu atau beberapa operasi baca, gunakan transaksi baca-tulis:
- Jika Anda harus melakukan satu atau beberapa operasi tulis secara atomik, lakukan penulisan tersebut dalam transaksi baca-tulis yang sama. Misalnya, jika Anda mentransfer $200 dari akun A ke akun B, lakukan kedua operasi tulis (mengurangi akun A sebesar $200 dan menambah akun B sebesar $200) dan pembacaan saldo akun awal dalam transaksi yang sama.
- Jika Anda ingin menggandakan saldo akun A, lakukan operasi baca dan tulis dalam transaksi yang sama. Hal ini memastikan sistem membaca saldo sebelum menggandakan dan memperbaruinya.
- Jika operasi tulis bergantung pada operasi baca, lakukan keduanya dalam transaksi baca-tulis yang sama, meskipun operasi tulis tidak dieksekusi. Misalnya, jika Anda ingin mentransfer $200 dari akun A ke akun B hanya jika saldo A lebih besar dari $500, sertakan pembacaan saldo A dan operasi penulisan bersyarat dalam transaksi yang sama, meskipun transfer tidak terjadi.
Untuk melakukan operasi baca, gunakan metode baca tunggal atau transaksi hanya baca:
- Jika Anda hanya melakukan operasi baca, dan Anda dapat mengekspresikan operasi baca menggunakan metode baca tunggal, gunakan metode baca tunggal atau transaksi hanya baca. Tidak seperti transaksi baca-tulis, bacaan tunggal tidak memperoleh kunci.
Isolasi repeatable read
Di Spanner, isolasi baca yang dapat diulang diimplementasikan menggunakan teknik yang dikenal sebagai isolasi snapshot. Isolasi baca berulang memastikan bahwa semua operasi baca dalam transaksi konsisten dengan database sebagaimana adanya pada awal transaksi. Hal ini juga menjamin bahwa penulisan serentak pada data yang sama hanya akan berhasil jika tidak ada konflik.
Dengan penguncian optimistis default, tidak ada kunci yang diperoleh hingga waktu penerapan jika data perlu ditulis. Jika ada konflik dengan data yang ditulis atau karena peristiwa sementara dalam Spanner seperti mulai ulang server, Spanner mungkin masih membatalkan transaksi. Karena operasi baca dalam transaksi baca-tulis tidak memperoleh kunci dalam isolasi repeatable read, tidak ada perbedaan antara menjalankan operasi hanya baca dalam transaksi hanya baca atau transaksi baca-tulis.
Pertimbangkan untuk menggunakan transaksi baca-tulis dalam isolasi baca yang dapat diulang dalam skenario berikut:
- Workload banyak melakukan operasi baca dan memiliki konflik penulisan yang rendah.
- Aplikasi mengalami hambatan performa karena penundaan dari persaingan kunci dan pembatalan transaksi yang disebabkan oleh transaksi lama dengan prioritas lebih tinggi yang mengganggu transaksi baru dengan prioritas lebih rendah untuk mencegah potensi kebuntuan (wound-wait).
- Aplikasi tidak memerlukan jaminan yang lebih ketat yang diberikan oleh tingkat isolasi serialisabel.
Saat melakukan operasi tulis yang bergantung pada satu atau beberapa operasi baca,
penyimpangan tulis dapat terjadi dalam isolasi baca yang dapat diulang. Penyimpangan tulis muncul dari
jenis update serentak tertentu, di mana setiap update diterima secara
independen, tetapi efek gabungannya melanggar integritas data aplikasi.
Oleh karena itu, pastikan Anda melakukan pembacaan yang merupakan bagian dari bagian penting transaksi dengan klausa FOR UPDATE atau petunjuk lock_scanned_ranges=exclusive untuk menghindari penulisan yang tidak sinkron. Untuk mengetahui informasi selengkapnya, lihat
Konflik baca-tulis dan kebenaran,
dan contoh yang dibahas dalam
Semantik baca-tulis.
Antarmuka
Library klien Spanner menyediakan antarmuka untuk mengeksekusi serangkaian tugas dalam transaksi baca-tulis, dengan percobaan ulang untuk pembatalan transaksi. Transaksi mungkin memerlukan beberapa kali percobaan ulang sebelum dilakukan.
Beberapa situasi dapat menyebabkan pembatalan transaksi. Misalnya, jika dua transaksi mencoba mengubah data secara bersamaan, kebuntuan dapat terjadi. Dalam kasus seperti itu, Spanner akan membatalkan satu transaksi agar transaksi lainnya dapat dilanjutkan. Lebih jarang, peristiwa sementara dalam Spanner juga dapat menyebabkan pembatalan transaksi.
Semua transaksi baca-tulis menyediakan properti ACID database relasional.
Karena transaksi bersifat atomik, transaksi yang dibatalkan tidak memengaruhi
database. Library klien Spanner mencoba ulang transaksi tersebut secara otomatis, tetapi jika Anda tidak menggunakan library klien, coba ulang transaksi dalam sesi yang sama untuk meningkatkan tingkat keberhasilan. Setiap percobaan ulang yang menghasilkan error
ABORTED akan meningkatkan prioritas penguncian transaksi. Selain itu,
driver klien Spanner menyertakan logika percobaan ulang transaksi internal
yang menyembunyikan error sementara dengan menjalankan ulang transaksi.
Saat menggunakan transaksi di library klien Spanner, Anda menentukan isi transaksi sebagai objek fungsi. Fungsi ini merangkum pembacaan dan penulisan yang dilakukan pada satu atau beberapa tabel database. Library klien Spanner menjalankan fungsi ini berulang kali hingga transaksi berhasil di-commit atau mengalami error yang tidak dapat dicoba ulang.
Contoh
Anggaplah Anda memiliki kolom MarketingBudget dalam
tabel Albums:
CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX), MarketingBudget INT64 ) PRIMARY KEY (SingerId, AlbumId);
Departemen pemasaran Anda meminta Anda memindahkan Rp2.000.000.000 dari anggaran Albums
(2, 2) ke Albums (1, 1), tetapi hanya jika dana tersedia dalam anggaran album tersebut. Anda harus menggunakan transaksi baca-tulis yang mengunci untuk operasi ini,
karena transaksi dapat melakukan penulisan, bergantung pada hasil pembacaan.
Contoh library klien berikut menunjukkan cara menjalankan transaksi baca-tulis menggunakan tingkat isolasi yang dapat diserialisasi default:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Untuk contoh cara menjalankan transaksi baca-tulis menggunakan isolasi repeatable read, lihat Menggunakan tingkat isolasi repeatable read.
Semantik
Bagian ini menjelaskan semantik untuk transaksi baca-tulis di Spanner.
Properti
Isolasi serialisabel adalah tingkat isolasi default di Spanner. Dengan isolasi yang dapat diserialisasi, Spanner memberikan jaminan kontrol konkurensi yang paling ketat untuk transaksi, yaitu konsistensi eksternal. Transaksi baca-tulis mengeksekusi serangkaian operasi baca dan tulis secara atomik. Operasi tulis dapat berlanjut tanpa diblokir oleh transaksi hanya baca. Stempel waktu saat transaksi baca-tulis dijalankan sesuai dengan waktu yang berlalu. Urutan serialisasi cocok dengan urutan stempel waktu ini.
Karena properti ini, sebagai developer aplikasi, Anda dapat berfokus pada kebenaran setiap transaksi dengan sendirinya, tanpa mengkhawatirkan cara melindungi eksekusinya dari transaksi lain yang mungkin dieksekusi pada saat yang sama.
Anda juga dapat menjalankan transaksi baca-tulis menggunakan isolasi baca yang dapat diulang. Isolasi repeatable read memastikan bahwa semua operasi baca dalam transaksi melihat snapshot kuat yang konsisten dari database sebagaimana adanya pada awal transaksi. Untuk mengetahui informasi selengkapnya, lihat Isolasi bacaan yang dapat diulang.
Transaksi baca-tulis dengan isolasi yang dapat diserialisasi
Setelah berhasil melakukan transaksi yang berisi serangkaian operasi baca dan tulis dalam isolasi yang dapat di-serialisasi default, hal berikut akan berlaku:
- Transaksi menampilkan nilai yang mencerminkan snapshot yang konsisten pada stempel waktu commit transaksi.
- Baris atau rentang kosong akan tetap kosong pada waktu penerapan.
- Transaksi meng-commit semua operasi tulis pada stempel waktu commit transaksi.
- Tidak ada transaksi yang dapat melihat penulisan hingga setelah transaksi di-commit.
Driver klien Spanner mencakup logika percobaan ulang transaksi yang menyembunyikan error sementara dengan menjalankan kembali transaksi dan memvalidasi data yang diamati klien.
Efeknya adalah semua operasi baca dan tulis tampak terjadi pada satu titik waktu, baik dari perspektif transaksi itu sendiri maupun dari perspektif pembaca dan penulis lain ke database Spanner. Artinya, operasi baca dan tulis terjadi pada stempel waktu yang sama. Sebagai contoh, lihat Serializability dan konsistensi eksternal.
Transaksi baca-tulis dengan isolasi baca yang dapat diulang
Setelah berhasil melakukan transaksi dengan isolasi baca yang dapat diulang, hal berikut berlaku:
- Transaksi menampilkan nilai yang mencerminkan snapshot database yang konsisten. Snapshot biasanya dibuat selama operasi transaksi pertama, yang mungkin tidak sama dengan stempel waktu penerapan.
- Karena repeatable read diimplementasikan menggunakan isolasi snapshot, transaksi meng-commit semua penulisan pada stempel waktu commit transaksi hanya jika set penulisan tidak berubah antara stempel waktu snapshot transaksi dan stempel waktu commit.
- Transaksi lain tidak akan melihat operasi tulis hingga setelah transaksi di-commit.
Isolasi untuk transaksi baca-tulis dengan operasi hanya baca
Saat transaksi baca-tulis hanya melakukan operasi baca, transaksi tersebut memberikan jaminan konsistensi yang serupa dengan transaksi hanya baca. Semua operasi baca dalam transaksi menampilkan data dari stempel waktu yang konsisten, termasuk konfirmasi baris yang tidak ada.
Salah satu perbedaannya adalah saat transaksi baca-tulis di-commit tanpa menjalankan operasi tulis. Dalam skenario ini, tidak ada jaminan bahwa data yang dibaca dalam transaksi tetap tidak berubah di database antara operasi baca dan commit transaksi.
Untuk memastikan keaktualan data dan memvalidasi bahwa data tidak dimodifikasi sejak pengambilan terakhir, pembacaan berikutnya diperlukan. Pembacaan ulang ini dapat dilakukan dalam transaksi baca-tulis lain atau dengan pembacaan yang kuat.
Untuk efisiensi yang optimal, jika transaksi hanya melakukan operasi baca, gunakan transaksi hanya baca, bukan transaksi baca-tulis, terutama saat menggunakan isolasi yang dapat diserialisasi.
Perbedaan serialisabilitas dan konsistensi eksternal dengan bacaan yang dapat diulang
Secara default, Spanner menawarkan jaminan transaksional yang kuat, termasuk serializability dan konsistensi eksternal. Properti ini memastikan bahwa data tetap konsisten dan operasi terjadi dalam urutan yang dapat diprediksi, bahkan dalam lingkungan terdistribusi.
Serialisasi memastikan bahwa semua transaksi tampak dieksekusi satu demi satu dalam urutan beruntun tunggal, meskipun diproses secara bersamaan. Spanner mencapai hal ini dengan menetapkan stempel waktu commit ke transaksi, yang mencerminkan urutan commitnya.
Spanner memberikan jaminan yang lebih kuat yang dikenal sebagai konsistensi eksternal. Artinya, tidak hanya transaksi yang di-commit dalam urutan yang tercermin oleh stempel waktu commit-nya, tetapi stempel waktu ini juga selaras dengan waktu di dunia nyata. Hal ini memungkinkan Anda membandingkan stempel waktu commit dengan waktu real-time, sehingga memberikan tampilan data yang konsisten dan diurutkan secara global.
Pada dasarnya, jika transaksi Txn1 di-commit sebelum transaksi Txn2 secara
real time, maka stempel waktu commit Txn1 lebih awal daripada stempel waktu
commit Txn2.
Perhatikan contoh berikut:
Dalam skenario ini, selama linimasa t:
- Transaksi
Txn1membaca dataA, melakukan penahapan penulisan keA, lalu berhasil di-commit. - Transaksi
Txn2dimulai setelahTxn1dimulai. Membaca dataBdan kemudian membaca dataA.
Meskipun Txn2 dimulai sebelum Txn1 selesai, Txn2 mengamati perubahan yang dilakukan oleh Txn1 pada A. Hal ini karena Txn2 membaca A setelah Txn1 melakukan
penulisan ke A.
Meskipun Txn1 dan Txn2 mungkin tumpang-tindih dalam waktu eksekusinya, stempel waktu commit, c1 dan c2 masing-masing, menerapkan urutan transaksi linear. Artinya:
- Semua operasi baca dan tulis dalam
Txn1tampaknya terjadi pada satu titik waktu,c1. - Semua operasi baca dan tulis dalam
Txn2tampaknya terjadi pada satu titik waktu,c2. - Yang penting,
c1lebih awal daric2untuk penulisan yang dilakukan, meskipun penulisan terjadi di komputer yang berbeda. JikaTxn2hanya melakukan pembacaan,c1lebih awal atau pada saat yang sama denganc2.
Pengurutan yang kuat ini berarti bahwa jika operasi baca berikutnya mengamati efek Txn2, operasi tersebut juga mengamati efek Txn1. Properti ini bernilai benar (true) untuk semua transaksi yang berhasil di-commit.
Di sisi lain, jika Anda menggunakan isolasi baca berulang, skenario berikut terjadi untuk transaksi yang sama:
Txn1dimulai dengan membaca dataA, membuat rekaman data sendiri dari database pada saat itu.Txn2kemudian dimulai, membaca dataB, dan membuat ringkasannya sendiri.- Selanjutnya,
Txn1mengubah dataA, dan berhasil melakukan perubahan. Txn2mencoba membaca dataA. Yang penting, karena beroperasi pada snapshot sebelumnya,Txn2tidak melihat pembaruan yang baru saja dilakukanTxn1padaA.Txn2membaca nilai yang lebih lama.Txn2mengubah dataBdan melakukan commit.
Dalam skenario ini, setiap transaksi beroperasi pada snapshot database yang konsisten, yang diambil dari saat transaksi dimulai. Urutan ini dapat menyebabkan anomali penulisan miring jika penulisan ke B oleh Txn2 secara logis bergantung pada nilai yang dibacanya dari A. Pada dasarnya, Txn2 membuat update berdasarkan informasi yang sudah tidak berlaku, dan penulisan berikutnya dapat melanggar invarian tingkat aplikasi. Untuk mencegah skenario ini terjadi, pertimbangkan untuk menggunakan SELECT...FOR UPDATE untuk isolasi baca yang dapat diulang, atau membuat batasan pemeriksaan dalam skema Anda.
Jaminan baca dan tulis saat transaksi gagal
Jika panggilan untuk mengeksekusi transaksi gagal, jaminan baca dan tulis yang Anda miliki bergantung pada error yang menyebabkan panggilan commit pokok gagal.
Spanner mungkin menjalankan operasi transaksi beberapa kali secara internal. Jika percobaan eksekusi gagal, error yang ditampilkan akan menentukan kondisi yang terjadi dan menunjukkan jaminan yang Anda terima. Namun, jika Spanner mencoba ulang transaksi Anda, efek samping dari operasinya (misalnya, perubahan pada sistem eksternal atau status sistem di luar database Spanner) dapat terjadi beberapa kali.
Jika transaksi Spanner gagal, jaminan yang Anda terima untuk operasi baca dan tulis bergantung pada error spesifik yang terjadi selama operasi commit.
Misalnya, pesan error seperti "Baris Tidak Ditemukan" atau "Baris Sudah Ada" menunjukkan masalah selama penulisan mutasi yang di-buffer. Hal ini dapat terjadi jika, misalnya, baris yang coba diupdate oleh klien tidak ada. Dalam skenario ini:
- Pembacaan konsisten: Data apa pun yang dibaca selama transaksi dijamin konsisten hingga titik error.
- Penulisan tidak diterapkan: Mutasi yang dicoba oleh transaksi tidak di-commit ke database.
- Konsistensi baris: Tidak adanya (atau status yang ada) baris yang memicu error konsisten dengan pembacaan yang dilakukan dalam transaksi.
Anda dapat membatalkan operasi baca asinkron di Spanner kapan saja tanpa memengaruhi operasi lain yang sedang berlangsung dalam transaksi yang sama. Fleksibilitas ini berguna jika operasi tingkat yang lebih tinggi dibatalkan, atau jika Anda memutuskan untuk membatalkan pembacaan berdasarkan hasil awal.
Namun, penting untuk dipahami bahwa meminta pembatalan pembacaan tidak menjamin penghentiannya secara langsung. Setelah permintaan pembatalan, operasi baca mungkin masih:
- Berhasil diselesaikan: pembacaan mungkin selesai diproses dan menampilkan hasil sebelum pembatalan berlaku.
- Gagal karena alasan lain: pembacaan dapat dihentikan karena kesalahan lain, seperti pembatalan.
- Menampilkan hasil yang tidak lengkap: pembacaan dapat menampilkan hasil parsial, yang kemudian divalidasi sebagai bagian dari proses commit transaksi.
Membatalkan operasi commit akan membatalkan seluruh transaksi, kecuali jika transaksi telah di-commit atau gagal karena alasan lain.
Atomisitas, konsistensi, durabilitas
Selain isolasi, Spanner memberikan jaminan properti ACID lainnya:
- Atomisitas: Transaksi dianggap atomik jika semua operasinya berhasil diselesaikan, atau tidak ada sama sekali. Jika ada operasi dalam transaksi yang gagal, seluruh transaksi akan di-roll back ke status aslinya, sehingga memastikan integritas data.
- Konsistensi: Transaksi harus menjaga integritas aturan dan batasan database. Setelah transaksi selesai, database harus dalam keadaan valid, mematuhi aturan yang telah ditentukan sebelumnya.
- Daya Tahan: Setelah transaksi dilakukan, perubahannya akan disimpan secara permanen di database dan tetap ada jika terjadi kegagalan sistem, pemadaman listrik, atau gangguan lainnya.
Performa
Bagian ini menjelaskan masalah yang memengaruhi performa transaksi baca-tulis.
Kontrol konkurensi penguncian
Secara default, Spanner mengizinkan beberapa klien berinteraksi dengan database yang sama secara bersamaan dalam tingkat isolasi serialisasi defaultnya. Untuk mempertahankan konsistensi data di seluruh transaksi serentak ini, Spanner memiliki mekanisme penguncian yang menggunakan kunci bersama dan eksklusif. Kunci baca ini hanya diperoleh untuk transaksi yang dapat diserialisasi, tetapi tidak untuk transaksi yang menggunakan isolasi baca yang dapat diulang.
Saat transaksi yang dapat diserialkan melakukan operasi baca, Spanner memperoleh kunci baca bersama pada data yang relevan. Kunci bersama ini memungkinkan operasi baca serentak lainnya mengakses data yang sama. Konkurensi ini dipertahankan hingga transaksi Anda bersiap untuk meng-commit perubahannya.
Dalam isolasi yang dapat di-serialisasi, selama fase commit, saat penulisan diterapkan, transaksi mencoba mengupgrade kuncinya menjadi kunci eksklusif. Untuk melakukannya, Spanner melakukan hal berikut:
- Memblokir permintaan kunci baca bersama baru pada data yang terpengaruh.
- Menunggu semua kunci baca bersama yang ada pada data tersebut dilepaskan.
- Setelah semua kunci baca bersama dihapus, kunci eksklusif akan ditempatkan, sehingga memberikan akses tunggal ke data selama penulisan.
Saat melakukan transaksi dalam isolasi baca berulang, transaksi mendapatkan kunci eksklusif untuk data yang ditulis. Transaksi mungkin harus menunggu kunci jika transaksi serentak juga melakukan operasi tulis ke data yang sama.
Catatan tentang kunci:
- Granularitas: Spanner menerapkan penguncian pada granularitas baris dan kolom. Artinya, jika transaksi
T1memegang kunci pada kolomAbarisalbumid, transaksiT2masih dapat menulis secara bersamaan ke kolomBdari barisalbumidyang sama tanpa konflik. Menulis tanpa membaca:
- Jika tidak ada pembacaan dalam transaksi, Spanner mungkin tidak memerlukan kunci eksklusif untuk penulisan tanpa pembacaan. Sebagai gantinya, ia mungkin menggunakan kunci bersama penulis. Hal ini karena urutan penerapan untuk penulisan tanpa pembacaan ditentukan oleh stempel waktu penerapan, sehingga beberapa penulis dapat beroperasi pada item yang sama secara bersamaan tanpa konflik. Penguncian eksklusif hanya diperlukan jika transaksi Anda pertama-tama membaca data yang akan ditulisnya.
- Dalam isolasi baca berulang, transaksi biasanya memperoleh kunci eksklusif untuk sel yang ditulis pada waktu commit.
Indeks sekunder untuk pencarian baris: dalam isolasi yang dapat diserialisasi, saat melakukan pembacaan dalam transaksi baca-tulis, penggunaan indeks sekunder dapat meningkatkan performa secara signifikan. Dengan menggunakan indeks sekunder untuk membatasi baris yang dipindai ke rentang yang lebih kecil, Spanner mengunci lebih sedikit baris dalam tabel, sehingga memungkinkan modifikasi baris serentak yang lebih besar di luar rentang tertentu tersebut.
Akses eksklusif resource eksternal: Kunci internal Spanner dirancang untuk konsistensi data dalam database Spanner itu sendiri. Jangan menggunakannya untuk menjamin akses eksklusif ke resource di luar Spanner. Spanner dapat membatalkan transaksi karena berbagai alasan, termasuk pengoptimalan sistem internal seperti pemindahan data di seluruh resource komputasi. Jika transaksi dicoba lagi (baik secara eksplisit oleh kode aplikasi Anda atau secara implisit oleh library klien seperti driver JDBC Spanner), kunci hanya dijamin telah dipegang selama upaya commit yang berhasil.
Statistik kunci: Untuk mendiagnosis dan menyelidiki konflik kunci dalam database Anda, gunakan alat introspeksi Statistik kunci.
Deteksi kebuntuan
Spanner mendeteksi saat beberapa transaksi mungkin mengalami kebuntuan
dan memaksa semua transaksi kecuali satu transaksi untuk dibatalkan. Pertimbangkan skenario ini:
Txn1 memegang kunci pada rekaman A dan menunggu kunci pada rekaman B, sementara
Txn2 memegang kunci pada rekaman B dan menunggu kunci pada rekaman A. Untuk
menyelesaikan masalah ini, salah satu transaksi harus dibatalkan, melepaskan kuncinya, dan
memungkinkan transaksi lainnya dilanjutkan.
Spanner menggunakan algoritma wound-wait standar untuk deteksi kebuntuan. Di balik layar, Spanner melacak usia setiap transaksi yang meminta kunci yang bertentangan. Memungkinkan transaksi lama membatalkan transaksi yang lebih baru. Transaksi lama adalah transaksi yang pembacaan, kueri, atau commit paling awalnya terjadi lebih awal.
Dengan memprioritaskan transaksi yang lebih lama, Spanner memastikan bahwa setiap transaksi pada akhirnya akan mendapatkan kunci setelah cukup lama untuk memiliki prioritas yang lebih tinggi. Misalnya, transaksi lama yang memerlukan kunci bersama penulis dapat membatalkan transaksi yang lebih baru yang memegang kunci bersama pembaca.
Eksekusi terdistribusi
Spanner dapat mengeksekusi transaksi pada data yang mencakup beberapa server, meskipun kemampuan ini memiliki biaya performa dibandingkan dengan transaksi server tunggal.
Jenis transaksi apa yang mungkin didistribusikan? Spanner dapat mendistribusikan tanggung jawab untuk baris database di banyak server. Biasanya, baris dan baris tabel yang disisipkan yang sesuai dilayani oleh server yang sama, seperti dua baris dalam tabel yang sama dengan kunci yang berdekatan. Spanner dapat melakukan transaksi di seluruh baris pada server yang berbeda. Namun, sebagai aturan umum, transaksi yang memengaruhi banyak baris yang ditempatkan bersama lebih cepat dan lebih murah daripada transaksi yang memengaruhi banyak baris yang tersebar di seluruh database atau tabel besar.
Transaksi yang paling efisien di Spanner hanya mencakup operasi baca dan tulis yang harus diterapkan secara atomik. Transaksi akan berjalan paling cepat jika semua pembacaan dan penulisan mengakses data di bagian ruang kunci yang sama.
Transaksi hanya baca
Selain mengunci transaksi baca-tulis, Spanner menawarkan transaksi hanya baca.
Gunakan transaksi hanya baca saat Anda perlu menjalankan lebih dari satu operasi baca pada stempel waktu yang sama. Jika Anda dapat mengekspresikan pembacaan menggunakan salah satu metode pembacaan tunggal Spanner, Anda harus menggunakan metode pembacaan tunggal tersebut. Performa penggunaan satu panggilan baca tersebut harus sebanding dengan performa satu baca yang dilakukan dalam transaksi hanya baca.
Jika Anda membaca data dalam jumlah besar, pertimbangkan untuk menggunakan partisi guna membaca data secara paralel.
Karena transaksi hanya baca tidak menulis, transaksi tersebut tidak memegang kunci dan tidak memblokir transaksi lain. Transaksi hanya baca mengamati awalan yang konsisten dari histori commit transaksi, sehingga aplikasi Anda selalu mendapatkan data yang konsisten.
Antarmuka
Spanner menyediakan antarmuka untuk menjalankan serangkaian tugas dalam konteks transaksi hanya baca, dengan percobaan ulang untuk pembatalan transaksi.
Contoh
Contoh berikut menunjukkan cara menggunakan transaksi hanya baca untuk mendapatkan data yang konsisten untuk dua pembacaan pada stempel waktu yang sama:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Semantik
Bagian ini menjelaskan semantik untuk transaksi hanya baca.
Transaksi hanya baca snapshot
Saat transaksi hanya baca dieksekusi di Spanner, transaksi tersebut melakukan semua pembacaannya pada satu titik waktu logis. Artinya, transaksi hanya baca dan pembaca serta penulis serentak lainnya melihat snapshot database yang konsisten pada saat tertentu.
Transaksi hanya baca snapshot ini menawarkan pendekatan yang lebih sederhana untuk pembacaan yang konsisten dibandingkan dengan transaksi baca-tulis penguncian. Berikut alasannya:
- Tanpa kunci: transaksi hanya baca tidak memperoleh kunci. Sebagai gantinya, opsi tersebut beroperasi dengan memilih stempel waktu Spanner dan menjalankan semua operasi baca terhadap versi historis data tersebut. Karena tidak menggunakan kunci, batch tidak akan memblokir transaksi baca-tulis serentak.
- Tidak ada pembatalan: transaksi ini tidak pernah dibatalkan. Meskipun dapat gagal jika stempel waktu baca yang dipilih dikumpulkan sampah, kebijakan pengumpulan sampah default Spanner biasanya cukup memadai sehingga sebagian besar aplikasi tidak akan mengalami masalah ini.
- Tidak ada commit atau roll back: transaksi hanya baca tidak memerlukan panggilan ke
sessions.commitatausessions.rollbackdan sebenarnya dicegah untuk melakukannya.
Untuk menjalankan transaksi snapshot, klien menentukan batas stempel waktu, yang menginstruksikan Spanner cara memilih stempel waktu baca. Jenis batas stempel waktu mencakup:
- Pembacaan yang andal: pembacaan ini menjamin bahwa Anda akan melihat efek semua transaksi yang dilakukan sebelum pembacaan dimulai. Semua baris dalam satu pembacaan konsisten. Namun, pembacaan kuat tidak dapat diulang, meskipun pembacaan kuat menampilkan stempel waktu, dan pembacaan lagi pada stempel waktu yang sama dapat diulang. Dua transaksi hanya baca yang kuat secara berurutan dapat menghasilkan hasil yang berbeda karena penulisan serentak. Kueri pada aliran perubahan harus menggunakan batas ini. Untuk mengetahui detail selengkapnya, lihat TransactionOptions.ReadOnly.strong.
- Keterlambatan yang tepat: opsi ini menjalankan pembacaan pada stempel waktu yang Anda tentukan, baik sebagai stempel waktu absolut atau sebagai durasi keterlambatan relatif terhadap waktu saat ini. Hal ini memastikan Anda mengamati awalan yang konsisten dari histori transaksi global hingga stempel waktu tersebut dan memblokir transaksi yang bertentangan yang mungkin dilakukan dengan stempel waktu yang kurang dari atau sama dengan stempel waktu baca. Meskipun sedikit lebih cepat daripada mode keusangan terbatas, mode ini dapat menampilkan data yang lebih lama. Untuk mengetahui detail selengkapnya, lihat TransactionOptions.ReadOnly.read_timestamp dan TransactionOptions.ReadOnly.exact_staleness.
- Keterlambatan yang dibatasi: Spanner memilih stempel waktu terbaru dalam batas keterlambatan yang ditentukan pengguna, sehingga memungkinkan eksekusi di replika terdekat yang tersedia tanpa pemblokiran. Semua baris yang ditampilkan konsisten. Seperti pembacaan kuat, keusangan terbatas tidak dapat diulang, karena pembacaan yang berbeda mungkin dieksekusi pada stempel waktu yang berbeda meskipun dengan batas yang sama. Operasi baca ini beroperasi dalam dua fase (negosiasi stempel waktu, lalu baca) dan biasanya sedikit lebih lambat daripada keaktualan yang tepat, tetapi sering kali menampilkan hasil yang lebih baru dan lebih mungkin dieksekusi di replika lokal. Mode ini hanya tersedia untuk transaksi hanya baca sekali pakai karena negosiasi stempel waktu mengharuskan mengetahui baris mana yang akan dibaca sebelumnya. Untuk detail selengkapnya, lihat TransactionOptions.ReadOnly.max_staleness dan TransactionOptions.ReadOnly.min_read_timestamp.
Transaksi DML yang dipartisi
Anda dapat menggunakan DML berpartisi untuk mengeksekusi pernyataan UPDATE dan DELETE skala besar tanpa mengalami batas transaksi atau mengunci seluruh tabel. Spanner mencapai hal ini dengan
mempartisi ruang kunci dan menjalankan pernyataan DML di setiap partisi
dalam transaksi baca-tulis terpisah.
Untuk menggunakan DML yang tidak dipartisi, Anda menjalankan pernyataan dalam transaksi baca-tulis yang Anda buat secara eksplisit dalam kode Anda. Untuk mengetahui detail selengkapnya, lihat Menggunakan DML.
Antarmuka
Spanner menyediakan antarmuka TransactionOptions.partitionedDml untuk menjalankan satu pernyataan DML terpartisi.
Contoh
Contoh kode berikut mengupdate kolom MarketingBudget dari tabel Albums.
C++
Anda menggunakan fungsi ExecutePartitionedDml() untuk menjalankan pernyataan DML berpartisi.
C#
Anda menggunakan metode ExecutePartitionedUpdateAsync() untuk menjalankan pernyataan DML berpartisi.
Go
Anda menggunakan metode PartitionedUpdate() untuk menjalankan pernyataan DML berpartisi.
Java
Anda menggunakan metode executePartitionedUpdate() untuk menjalankan pernyataan DML berpartisi.
Node.js
Anda menggunakan metode runPartitionedUpdate() untuk menjalankan pernyataan DML berpartisi.
PHP
Anda menggunakan metode executePartitionedUpdate() untuk menjalankan pernyataan DML berpartisi.
Python
Anda menggunakan metode execute_partitioned_dml() untuk menjalankan pernyataan DML berpartisi.
Ruby
Anda menggunakan metode execute_partitioned_update() untuk menjalankan pernyataan DML berpartisi.
Contoh kode berikut menghapus baris dari tabel Singers, berdasarkan kolom
SingerId.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Semantik
Bagian ini menjelaskan semantik untuk DML yang dipartisi.
Memahami eksekusi DML yang dipartisi
Anda hanya dapat menjalankan satu pernyataan DML berpartisi dalam satu waktu, baik Anda menggunakan metode library klien atau Google Cloud CLI.
Transaksi yang dipartisi tidak mendukung commit atau rollback. Spanner akan segera mengeksekusi dan menerapkan pernyataan DML. Jika Anda membatalkan operasi, atau operasi gagal, Spanner akan membatalkan semua partisi yang sedang dieksekusi dan tidak memulai partisi yang tersisa. Namun, Spanner tidak mengembalikan partisi yang telah dieksekusi.
Strategi perolehan kunci DML yang dipartisi
Untuk mengurangi pertentangan kunci, DML berpartisi hanya memperoleh kunci baca pada baris yang cocok dengan klausa WHERE. Transaksi independen yang lebih kecil yang digunakan untuk setiap partisi juga memegang kunci dalam waktu yang lebih singkat.
Stempel waktu baca lama dan pembersihan sampah memori versi
Spanner melakukan pembersihan sampah memori versi untuk mengumpulkan data yang dihapus atau ditimpa dan mengklaim kembali penyimpanan. Secara default, data yang lebih lama dari satu jam akan diklaim kembali. Spanner tidak dapat melakukan pembacaan pada stempel waktu yang lebih lama dari VERSION_RETENTION_PERIOD yang dikonfigurasi, yang secara default adalah satu jam, tetapi dapat dikonfigurasi hingga satu minggu. Jika pembacaan menjadi terlalu lama selama eksekusi, pembacaan tersebut akan gagal dan menampilkan error FAILED_PRECONDITION.
Kueri pada aliran perubahan
Aliran perubahan adalah objek skema yang dapat Anda konfigurasi untuk memantau modifikasi data di seluruh database, tabel tertentu, atau sekumpulan kolom yang ditentukan dalam database.
Saat Anda membuat aliran data perubahan, Spanner akan menentukan
fungsi bernilai tabel (TVF) SQL yang sesuai. Anda dapat menggunakan TVF ini untuk membuat kueri
catatan perubahan di aliran perubahan terkait dengan
metode sessions.executeStreamingSql. Nama TVF dibuat dari nama aliran perubahannya dan selalu
dimulai dengan READ_.
Semua kueri pada TVF aliran perubahan harus dieksekusi menggunakan
API sessions.executeStreamingSql dalam transaksi hanya baca sekali pakai
dengan timestamp_bound hanya baca yang kuat. TVF aliran perubahan memungkinkan Anda
menentukan start_timestamp dan end_timestamp untuk rentang waktu. Semua catatan perubahan dalam periode retensi dapat diakses menggunakan timestamp_bound hanya baca yang kuat ini. Semua
TransactionOptions lainnya
tidak valid untuk kueri aliran perubahan.
Selain itu, jika
TransactionOptions.read_only.return_read_timestamp
disetel ke true, pesan
Transaction yang menjelaskan
transaksi akan menampilkan nilai khusus 2^63 - 2, bukan stempel waktu
baca yang valid. Anda harus menghapus nilai khusus ini dan tidak menggunakannya untuk kueri berikutnya.
Untuk mengetahui informasi selengkapnya, lihat Alur kerja kueri aliran perubahan.
Transaksi Tidak Aktif
Transaksi dianggap tidak aktif jika tidak ada pembacaan atau kueri SQL yang belum selesai
dan belum memulai transaksi dalam 10 detik terakhir. Spanner dapat membatalkan transaksi yang tidak aktif untuk mencegahnya menahan kunci tanpa batas. Jika transaksi
yang tidak aktif dibatalkan, commit akan gagal dan menampilkan error ABORTED.
Menjalankan kueri kecil secara berkala, seperti SELECT 1, dalam transaksi dapat mencegah transaksi menjadi tidak aktif.
Langkah berikutnya
- Pelajari lebih lanjut tingkat isolasi Spanner.