Kapan menggunakan database berbasis CRDT

Roshan Kumar adalah manajer produk senior di Redis Labs.

Membengkokkan konsistensi dan ketersediaan seperti yang dijelaskan oleh teorema CAP telah menjadi tantangan besar bagi arsitek aplikasi terdistribusi geografis. Partisi jaringan tidak dapat dihindari. Latensi yang tinggi antar pusat data selalu menyebabkan terputusnya hubungan antar pusat data untuk waktu yang singkat. Dengan demikian, arsitektur tradisional untuk aplikasi yang terdistribusi secara geografis dirancang untuk memberikan konsistensi data atau mengurangi ketersediaan.

Sayangnya, Anda tidak dapat mengorbankan ketersediaan untuk aplikasi pengguna interaktif. Belakangan ini, para arsitek telah mengambil bidikan pada konsistensi dan menganut model konsistensi akhirnya. Dalam model ini, aplikasi bergantung pada sistem manajemen database untuk menggabungkan semua salinan lokal dari data untuk membuatnya konsisten.

Semuanya terlihat bagus dengan model konsistensi akhir hingga ada konflik data. Beberapa model konsistensi akhirnya menjanjikan upaya terbaik untuk memperbaiki konflik, tetapi gagal menjamin konsistensi yang kuat. Kabar baiknya adalah, model yang dibangun di sekitar tipe data yang direplikasi bebas konflik (CRDT) memberikan konsistensi akhir yang kuat.

CRDT mencapai konsistensi akhir yang kuat melalui seperangkat aturan dan semantik resolusi konflik yang telah ditentukan sebelumnya. Aplikasi yang dibangun di atas database berbasis CRDT harus dirancang untuk mengakomodasi semantik resolusi konflik. Pada artikel ini kita akan membahas bagaimana merancang, mengembangkan, dan menguji aplikasi yang terdistribusi secara geografis menggunakan database berbasis CRDT. Kami juga akan memeriksa empat contoh kasus penggunaan: penghitung, cache terdistribusi, sesi bersama, dan penyerapan data multi-region.

Perusahaan saya, Redis Labs, baru-baru ini mengumumkan dukungan CRDT di Redis Enterprise, dengan tipe data replikasi bebas konflik yang bergabung dengan portofolio kaya struktur data — String, Hash, Daftar, Kumpulan, Kumpulan yang Diurutkan, Bitfields, Geo, Hyperloglog, dan Aliran — di produk database kami. Namun, diskusi berikut ini tidak hanya berlaku untuk Redis Enterprise, tetapi juga untuk semua database berbasis CRDT.

Database untuk aplikasi yang terdistribusi secara geografis

Untuk aplikasi yang terdistribusi secara geografis, biasanya menjalankan layanan secara lokal ke klien. Ini mengurangi lalu lintas jaringan dan latensi yang disebabkan oleh perjalanan bolak-balik. Dalam banyak kasus, arsitek merancang layanan untuk disambungkan ke database lokal. Kemudian muncul pertanyaan tentang bagaimana Anda mempertahankan data yang konsisten di semua database. Salah satu opsinya adalah menanganinya di tingkat aplikasi — Anda dapat menulis proses pekerjaan berkala yang akan menyinkronkan semua database. Atau Anda bisa mengandalkan database yang akan menyinkronkan data antar database.

Untuk sisa artikel ini, kami berasumsi bahwa Anda akan menggunakan opsi kedua — biarkan database yang bekerja. Seperti yang ditunjukkan pada Gambar 1 di bawah, aplikasi Anda yang terdistribusi secara geografis menjalankan layanan di beberapa region, dengan setiap layanan terhubung ke database lokal. Sistem manajemen basis data yang mendasari menyinkronkan data antara basis data yang digunakan di seluruh wilayah.

Redis Labs

Model konsistensi data

Model konsistensi adalah kontrak antara database terdistribusi dan aplikasi yang menentukan seberapa bersih data antara operasi tulis dan baca.

Misalnya, dalam model konsistensi yang kuat, database menjamin bahwa aplikasi akan selalu membaca tulisan terakhir. Dengan konsistensi sekuensial, database memastikan bahwa urutan data yang Anda baca konsisten dengan urutan penulisan ke database. Dalam model konsistensi akhirnya, database terdistribusi berjanji untuk menyinkronkan dan mengkonsolidasikan data antara replika database di belakang layar. Oleh karena itu, jika Anda menulis data ke satu replika database dan membacanya dari replika database lainnya, Anda mungkin tidak akan membaca salinan data terbaru.

Konsistensi yang kuat

Komitmen dua fase adalah teknik umum untuk mencapai konsistensi yang kuat. Di sini, untuk setiap operasi tulis (tambah, perbarui, hapus) pada node database lokal, node database menyebarkan perubahan ke semua node database dan menunggu semua node mengakui. Node lokal kemudian mengirimkan komit ke semua node dan menunggu pengakuan lain. Aplikasi akan dapat membaca data hanya setelah komit kedua. Database terdistribusi tidak akan tersedia untuk operasi tulis ketika jaringan terputus antara database.

Konsistensi akhirnya

Keuntungan utama dari model konsistensi akhir adalah bahwa database akan tersedia bagi Anda untuk melakukan operasi tulis bahkan ketika konektivitas jaringan antara replika database terdistribusi rusak. Secara umum, model ini menghindari waktu bolak-balik yang disebabkan oleh commit dua fase, dan oleh karena itu mendukung lebih banyak operasi tulis per detik daripada model lainnya. Satu masalah yang akhirnya harus diatasi oleh konsistensi adalah konflik — penulisan simultan pada item yang sama di dua lokasi berbeda. Berdasarkan cara mereka menghindari atau menyelesaikan konflik, database yang pada akhirnya konsisten diklasifikasikan lebih lanjut dalam kategori berikut:

  1. Penulis terakhir menang (LWW).  Dalam strategi ini, database terdistribusi mengandalkan sinkronisasi stempel waktu antara server. Basis data bertukar stempel waktu dari setiap operasi tulis bersama dengan datanya sendiri. Jika ada konflik, operasi tulis dengan stempel waktu terbaru yang menang.

    Kerugian dari teknik ini adalah bahwa teknik ini mengasumsikan semua jam sistem disinkronkan. Dalam praktiknya, sulit dan mahal untuk menyinkronkan semua jam sistem.

  2. Konsistensi akhir berbasis kuorum: Teknik ini mirip dengan komitmen dua fase. Namun, database lokal tidak menunggu pengakuan dari semua database; itu hanya menunggu pengakuan dari mayoritas database. Pengakuan dari mayoritas membentuk kuorum. Jika ada konflik, operasi tulis yang telah menetapkan kuorum menang.

    Di sisi lain, teknik ini menambahkan latensi jaringan ke operasi tulis, yang membuat aplikasi kurang skalabel. Selain itu, database lokal tidak akan tersedia untuk penulisan jika diisolasi dari replika database lain di topologi.

  3. Gabungkan replikasi: Dalam pendekatan tradisional ini, yang umum di antara database relasional, agen gabungan terpusat menggabungkan semua data. Metode ini juga menawarkan beberapa fleksibilitas dalam menerapkan aturan Anda sendiri untuk menyelesaikan konflik.

    Penggabungan replikasi terlalu lambat untuk mendukung aplikasi yang menarik secara real-time. Ini juga memiliki satu titik kegagalan. Karena metode ini tidak mendukung aturan yang telah ditetapkan sebelumnya untuk resolusi konflik, metode ini sering kali menyebabkan implementasi buggy untuk resolusi konflik.

  4. Tipe data direplikasi bebas konflik (CRDT): Anda akan mempelajari CRDT secara mendetail di beberapa bagian berikutnya. Singkatnya, database berbasis CRDT mendukung jenis data dan operasi yang memberikan konsistensi akhir tanpa konflik. Database berbasis CRDT tersedia bahkan ketika replika database terdistribusi tidak dapat bertukar data. Mereka selalu memberikan latensi lokal ke operasi baca dan tulis.

    Keterbatasan? Tidak semua kasus penggunaan database mendapatkan keuntungan dari CRDT. Selain itu, semantik resolusi konflik untuk database berbasis CRDT sudah ditentukan sebelumnya dan tidak dapat diganti.

Apa itu CRDT?

CRDT adalah tipe data khusus yang menyatukan data dari semua replika database. CRDT yang populer adalah G-counter (penghitung khusus pertumbuhan), penghitung PN (penghitung positif-negatif), register, G-set (set hanya tumbuh), set 2P (set dua fase), OR-set ( observasi-hapus set), dll. Di balik layar, mereka mengandalkan properti matematika berikut untuk menyatukan data:

  1. Properti komutatif: a ☆ b = b ☆ a
  2. Properti asosiatif: a ☆ (b ☆ c) = (a ☆ b) ☆ c
  3. Idempotensi:  a ☆ a = a

G-counter adalah contoh sempurna dari CRDT operasional yang menggabungkan operasi. Di sini, a + b = b + a dan a + (b + c) = (a + b) + c. Replika hanya bertukar pembaruan (tambahan) satu sama lain. CRDT akan menggabungkan pembaruan dengan menambahkannya. G-set, misalnya, menerapkan idempotensi ({a, b, c} U {c} = {a, b, c}) untuk menggabungkan semua elemen. Idempotensi menghindari duplikasi elemen yang ditambahkan ke struktur data saat mereka bergerak dan berkumpul melalui jalur yang berbeda.

Tipe data CRDT dan semantik resolusi konfliknya

Struktur data bebas konflik: G-counter, PN-counters, G-Sets

Semua struktur data ini dirancang bebas konflik. Tabel di bawah ini menunjukkan bagaimana data disinkronkan antara replika database.

Redis Labs Redis Labs

G-counters dan PN-counters populer untuk kasus penggunaan seperti pemungutan suara global, penghitungan aliran, pelacakan aktivitas, dan sebagainya. G-set banyak digunakan untuk mengimplementasikan teknologi blockchain. Bitcoin, misalnya, menggunakan entri blockchain hanya-tambahan.

Register: String, Hash

Register pada dasarnya tidak bebas konflik. Mereka biasanya mengikuti kebijakan SPL atau resolusi konflik berbasis kuorum. Gambar 4 menunjukkan contoh bagaimana register menyelesaikan konflik dengan mengikuti kebijakan LWW.

Redis Labs

Register terutama digunakan untuk menyimpan data cache dan sesi, informasi profil pengguna, katalog produk, dll.

2P-set

Rangkaian dua fase mempertahankan dua set G-set — satu untuk item yang ditambahkan dan yang lainnya untuk item yang dihapus. Replika menukar penambahan G-set saat disinkronkan. Konflik muncul ketika elemen yang sama ditemukan di kedua set. Di beberapa database berbasis CRDT seperti Redis Enterprise, hal ini ditangani oleh kebijakan, "Tambahkan kemenangan atas penghapusan".

Redis Labs

Set 2P adalah struktur data yang baik untuk menyimpan data sesi bersama seperti keranjang belanja, dokumen bersama, atau spreadsheet.

Bagaimana merancang aplikasi untuk menggunakan database berbasis CRDT

Menghubungkan aplikasi Anda ke database berbasis CRDT tidak berbeda dengan menghubungkan aplikasi Anda ke database lain. Namun, karena kebijakan konsistensi akhirnya, aplikasi Anda harus mengikuti sekumpulan aturan tertentu untuk memberikan pengalaman pengguna yang konsisten. Tiga kunci: 

  1. Jadikan aplikasi Anda tanpa kewarganegaraan. Aplikasi stateless biasanya digerakkan oleh API. Setiap panggilan ke API menghasilkan rekonstruksi pesan lengkap dari awal. Ini memastikan bahwa Anda selalu menarik salinan data yang bersih kapan saja. Latensi lokal rendah yang ditawarkan oleh database berbasis CRDT membuat rekonstruksi pesan lebih cepat dan mudah. 

  2. Pilih CRDT yang tepat yang sesuai dengan kasus penggunaan Anda. Penghitung adalah CRDT yang paling sederhana. Ini dapat diterapkan untuk kasus penggunaan seperti pemungutan suara global, pelacakan sesi aktif, pengukuran, dll. Namun, jika Anda ingin menggabungkan status objek terdistribusi, Anda juga harus mempertimbangkan struktur data lain. Misalnya, untuk aplikasi yang memungkinkan pengguna mengedit dokumen bersama, Anda mungkin ingin mempertahankan tidak hanya pengeditan, tetapi juga urutan pelaksanaannya. Dalam hal ini, menyimpan hasil edit dalam daftar berbasis CRDT atau struktur data antrian akan menjadi solusi yang lebih baik daripada menyimpannya dalam register. Penting juga bagi Anda untuk memahami semantik resolusi konflik yang diberlakukan oleh CRDT, dan bahwa solusi Anda sesuai dengan aturan.
  3. CRDT bukanlah solusi satu ukuran untuk semua. Meskipun CRDT memang alat yang hebat untuk banyak kasus penggunaan, CRDT mungkin bukan yang terbaik untuk semua kasus penggunaan (misalnya transaksi ACID). Database berbasis CRDT umumnya sesuai dengan arsitektur layanan mikro di mana Anda memiliki database khusus untuk setiap layanan mikro.

Kesimpulan utama di sini adalah bahwa aplikasi Anda harus fokus pada logika dan mendelegasikan pengelolaan data dan kompleksitas sinkronisasi ke database yang mendasarinya.

Menguji aplikasi dengan database multi-master terdistribusi

Untuk mencapai go-to-market yang lebih cepat, kami menyarankan Anda untuk memiliki pengembangan, pengujian, penahapan, dan penyiapan produksi yang konsisten. Antara lain, itu berarti penyiapan pengembangan dan pengujian Anda harus memiliki model miniatur dari database terdistribusi Anda. Periksa apakah database berbasis CRDT Anda tersedia sebagai kontainer Docker atau alat virtual. Terapkan replika database Anda di subnet yang berbeda sehingga Anda dapat menyimulasikan penyiapan cluster yang terhubung dan terputus.

Menguji aplikasi dengan database multi-master terdistribusi mungkin terdengar rumit. Tetapi sebagian besar waktu yang akan Anda uji adalah konsistensi data dan ketersediaan aplikasi dalam dua situasi: Ketika database terdistribusi terhubung, dan ketika ada partisi jaringan di antara database.

Dengan menyiapkan database terdistribusi tiga node di lingkungan pengembangan, Anda dapat mencakup (dan bahkan mengotomatiskan) sebagian besar skenario pengujian dalam pengujian unit. Berikut adalah pedoman dasar untuk menguji aplikasi Anda: