TrueTime adalah clock terdistribusi yang sangat tersedia dan disediakan untuk aplikasi di semua server Google1. TrueTime memungkinkan aplikasi membuat stempel waktu yang meningkat secara monoton: aplikasi dapat menghitung stempel waktu T yang dijamin lebih besar daripada stempel waktu T', jika T' selesai dibuat sebelum T mulai dibuat. Jaminan ini berlaku di semua server dan semua stempel waktu.
Fitur TrueTime ini digunakan oleh Spanner untuk menetapkan stempel waktu ke transaksi. Secara khusus, setiap transaksi diberi stempel waktu yang mencerminkan saat Spanner menganggap transaksi tersebut telah terjadi. Karena Spanner menggunakan kontrol konkurensi multi-versi (MVCC), jaminan pengurutan pada stempel waktu memungkinkan klien Spanner melakukan pembacaan yang konsisten di seluruh database (bahkan di beberapa region Cloud) tanpa memblokir penulisan.
Konsistensi eksternal
Jika tingkat isolasi tidak ditentukan, atau jika Anda menetapkan tingkat isolasi sebagai isolasi yang dapat diserialisasi, Spanner akan memberikan jaminan kontrol konkurensi yang paling ketat untuk transaksi kepada klien, yang disebut konsistensi eksternal2. Dalam konsistensi eksternal, sistem berperilaku seolah-olah semua transaksi berjalan secara berurutan, meskipun Spanner sebenarnya menjalankannya di beberapa server (dan mungkin di beberapa pusat data) untuk performa dan ketersediaan yang lebih tinggi. Selain itu, jika satu transaksi selesai sebelum transaksi lain mulai di-commit, sistem menjamin bahwa klien tidak akan pernah melihat status yang mencakup efek transaksi kedua, tetapi tidak mencakup transaksi pertama. Secara intuitif, Spanner tidak dapat dibedakan secara semantik dari database satu mesin. Meskipun memberikan jaminan yang kuat, Spanner memungkinkan aplikasi mencapai performa yang sebanding dengan database yang memberikan jaminan yang lebih lemah (sebagai imbalan atas performa yang lebih tinggi). Secara default, Spanner memungkinkan penulisan berlanjut tanpa diblokir oleh transaksi hanya baca, tetapi tanpa menunjukkan anomali yang diizinkan oleh isolasi repeatable read.
Di sisi lain, isolasi repeatable read memastikan bahwa semua operasi baca dalam transaksi melihat snapshot database yang konsisten seperti yang ada di awal transaksi. Pendekatan ini bermanfaat dalam skenario konkurensi baca-tulis tinggi di mana banyak transaksi membaca data yang mungkin dimodifikasi oleh transaksi lain. Untuk mengetahui informasi selengkapnya, lihat isolasi bacaan yang dapat diulang.
Konsistensi eksternal sangat menyederhanakan pengembangan aplikasi. Misalnya, anggaplah Anda telah membuat aplikasi perbankan di Spanner dan salah satu pelanggan Anda memulai dengan saldo Rp500.000 di rekening giro dan Rp500.000 di rekening tabungannya. Kemudian, aplikasi Anda memulai alur kerja yang pertama-tama melakukan transaksi T1 untuk menyetor $200 ke rekening tabungan, lalu mengeluarkan transaksi kedua T2 untuk mendebit $150 dari rekening giro. Selain itu, asumsikan bahwa pada akhir hari, saldo negatif di satu akun akan otomatis ditutupi dari akun lain, dan pelanggan akan dikenai penalti jika total saldo di semua akunnya negatif kapan saja selama hari itu. Konsistensi eksternal menjamin bahwa karena T2 mulai melakukan commit setelah T1 selesai, maka semua pembaca database akan mengamati bahwa penyetoran T1 terjadi sebelum pendebitan T2. Dengan kata lain, konsistensi eksternal menjamin bahwa tidak ada seorang pun yang akan melihat status saat T2 terjadi sebelum T1; dengan kata lain, pendebitan tidak akan dikenai penalti karena dana tidak mencukupi.
Database tradisional yang menggunakan penyimpanan versi tunggal dan penguncian dua fase yang ketat memberikan konsistensi eksternal. Sayangnya, dalam sistem seperti itu, setiap kali aplikasi Anda ingin membaca data terbaru (yang kami sebut "pembacaan kuat"), sistem akan mendapatkan kunci baca pada data, yang memblokir penulisan ke data yang sedang dibaca.
Stempel waktu dan MVCC
Untuk membaca tanpa memblokir penulisan, Spanner dan banyak sistem database lainnya menyimpan beberapa versi data yang tidak dapat diubah (sering disebut kontrol serentak multi-versi). Operasi tulis membuat versi baru yang tidak dapat diubah dan stempel waktunya adalah stempel waktu transaksi operasi tulis. "Pembacaan snapshot" pada stempel waktu akan menampilkan nilai versi terbaru sebelum stempel waktu tersebut, dan tidak perlu memblokir penulisan. Oleh karena itu, stempel waktu yang ditetapkan ke versi harus konsisten dengan urutan transaksi yang dapat diamati untuk di-commit. Kami menyebut properti ini "pemberian stempel waktu yang tepat", yang setara dengan konsistensi eksternal.
Untuk melihat mengapa pemberian stempel waktu yang tepat itu penting, pertimbangkan contoh perbankan dari bagian sebelumnya. Tanpa stempel waktu yang tepat, T2 mungkin diberi stempel waktu yang lebih awal daripada stempel waktu yang diberikan ke T1 (misalnya, jika sistem hipotetis menggunakan jam lokal, bukan TrueTime, dan jam server yang memproses T2 tertinggal sedikit). Pembacaan snapshot kemudian dapat mencerminkan pendebitan dari T2, tetapi tidak mencerminkan penyetoran T1, meskipun pelanggan melihat penyetoran selesai sebelum memulai pendebitan.
Pemberian stempel waktu yang tepat sangatlah mudah untuk database satu mesin (misalnya, Anda cukup menetapkan stempel waktu dari penghitung global yang meningkat secara monoton). Mencapainya dalam sistem yang didistribusikan secara luas seperti Spanner, yang servernya di seluruh dunia perlu menetapkan stempel waktu, jauh lebih sulit dilakukan secara efisien.
Spanner bergantung pada TrueTime untuk menghasilkan stempel waktu yang meningkat secara monoton. Spanner menggunakan stempel waktu ini dalam dua cara. Pertama, fitur ini menggunakannya sebagai stempel waktu yang tepat untuk transaksi tulis tanpa memerlukan komunikasi global. Kedua, menggunakan stempel waktu tersebut sebagai stempel waktu untuk operasi baca yang kuat, yang memungkinkan operasi baca yang kuat dieksekusi dalam satu putaran komunikasi, bahkan operasi baca yang kuat yang mencakup beberapa server.
FAQ
Jaminan konsistensi apa yang disediakan Spanner?
Secara default, Spanner menyediakan konsistensi eksternal, yang merupakan properti konsistensi paling ketat untuk sistem pemrosesan transaksi. Semua transaksi di Spanner yang menggunakan isolasi serialisasi memenuhi properti konsistensi ini, bukan hanya yang berada dalam partisi. Untuk mengetahui informasi selengkapnya, lihat Ringkasan tingkat isolasi.
Konsistensi eksternal menyatakan bahwa Spanner mengeksekusi transaksi dengan cara yang tidak dapat dibedakan dari sistem tempat transaksi dieksekusi secara serial, dan lebih lanjut lagi, bahwa urutan serial konsisten dengan urutan transaksi yang dapat diamati untuk di-commit. Karena stempel waktu yang dibuat untuk transaksi sesuai dengan urutan serial, jika ada klien yang melihat transaksi T2 mulai di-commit setelah transaksi T1 selesai, sistem akan menetapkan stempel waktu ke T2 yang lebih tinggi daripada stempel waktu T1.
Apakah Spanner menyediakan linearizability?
Ya. Secara default, Spanner menyediakan konsistensi eksternal, yang merupakan properti yang lebih kuat daripada linearizability, karena linearizability tidak mengatakan apa pun tentang perilaku transaksi. Linearizability adalah properti objek serentak yang mendukung operasi baca dan tulis atomik. Dalam database, "objek" biasanya berupa satu baris atau bahkan satu sel. Konsistensi eksternal adalah properti sistem pemrosesan transaksi, tempat klien mensintesis transaksi secara dinamis yang berisi beberapa operasi baca dan tulis pada objek arbitrer. Linearizability dapat dilihat sebagai kasus khusus dari konsistensi eksternal, di mana transaksi hanya dapat berisi satu operasi baca atau tulis pada satu objek.
Apakah Spanner menyediakan serialisabilitas?
Ya. Secara default, Spanner memberikan konsistensi eksternal, yang merupakan properti yang lebih ketat daripada serialisabilitas. Sistem pemrosesan transaksi dapat diserialkan jika menjalankan transaksi dengan cara yang tidak dapat dibedakan dari sistem yang menjalankan transaksi secara serial. Spanner juga menjamin bahwa urutan serial konsisten dengan urutan transaksi yang dapat diamati untuk di-commit.
Pertimbangkan kembali contoh perbankan yang digunakan sebelumnya. Dalam sistem yang menyediakan serialisabilitas, tetapi bukan konsistensi eksternal, meskipun pelanggan menjalankan T1, lalu T2 secara berurutan, sistem akan diizinkan untuk mengurutkannya ulang, yang dapat menyebabkan debit dikenai penalti karena dana tidak mencukupi.
Apakah Spanner memberikan konsistensi kuat?
Ya. Spanner memberikan konsistensi eksternal, yang merupakan properti yang lebih kuat daripada konsistensi kuat. Mode default untuk pembacaan di Spanner adalah "kuat", yang menjamin bahwa pembacaan tersebut mengamati efek semua transaksi yang di-commit sebelum dimulainya operasi, terlepas dari replika mana yang menerima pembacaan.
Apa perbedaan antara konsistensi kuat dan konsistensi eksternal?
Protokol replikasi menunjukkan konsistensi yang kuat jika objek yang direplikasi dapat dilinearisasi. Seperti linearisabilitas, konsistensi kuat lebih lemah daripada konsistensi eksternal, karena tidak memberlakukan apa pun tentang perilaku transaksi.
Apakah Spanner menyediakan konsistensi pada akhirnya (atau lambat)?
Spanner memberikan konsistensi eksternal, yang merupakan properti yang jauh lebih kuat daripada konsistensi pada akhirnya. Konsistensi pada akhirnya mengorbankan jaminan yang lebih lemah untuk performa yang lebih tinggi. Konsistensi tertunda bermasalah karena artinya pembaca dapat mengamati database dalam status yang tidak pernah ada (misalnya, pembacaan dapat mengamati status saat Transaksi B dilakukan, tetapi Transaksi A tidak, meskipun A terjadi sebelum B).
Spanner menyediakan pembacaan basi, yang menawarkan manfaat performa serupa dengan konsistensi tertunda, tetapi dengan jaminan konsistensi yang jauh lebih kuat. Pembacaan yang tidak valid menampilkan data dari stempel waktu sebelumnya, yang tidak dapat memblokir penulisan karena versi data sebelumnya tidak dapat diubah.