Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Hei Habr!

Kami mengingatkan Anda bahwa berikut buku tentang Kafka kami telah menerbitkan karya yang sama menariknya tentang perpustakaan API Aliran Kafka.

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Untuk saat ini, komunitas baru mempelajari batasan dari alat canggih ini. Jadi, sebuah artikel baru-baru ini diterbitkan, terjemahannya ingin kami perkenalkan kepada Anda. Dari pengalamannya sendiri, penulis menceritakan cara mengubah Kafka Streams menjadi penyimpanan data terdistribusi. Selamat membaca!

perpustakaan Apache Aliran Kafka digunakan di seluruh dunia di perusahaan untuk pemrosesan aliran terdistribusi di atas Apache Kafka. Salah satu aspek yang kurang dihargai dari kerangka kerja ini adalah memungkinkan Anda menyimpan keadaan lokal yang dihasilkan berdasarkan pemrosesan thread.

Pada artikel ini, saya akan memberi tahu Anda bagaimana perusahaan kami berhasil memanfaatkan peluang ini secara menguntungkan ketika mengembangkan produk untuk keamanan aplikasi cloud. Dengan menggunakan Kafka Streams, kami membuat layanan mikro negara bersama, yang masing-masing berfungsi sebagai sumber informasi andal yang toleran terhadap kesalahan dan sangat tersedia tentang keadaan objek dalam sistem. Bagi kami, ini merupakan langkah maju baik dari segi keandalan dan kemudahan dukungan.

Jika Anda tertarik dengan pendekatan alternatif yang memungkinkan Anda menggunakan satu database pusat untuk mendukung keadaan formal objek Anda, bacalah, ini akan menarik...

Mengapa kami pikir ini saatnya mengubah cara kami bekerja dengan negara bersama

Kami perlu menjaga status berbagai objek berdasarkan laporan agen (misalnya: apakah situs sedang diserang)? Sebelum bermigrasi ke Kafka Streams, kami sering mengandalkan satu database pusat (+ API layanan) untuk pengelolaan negara. Pendekatan ini memiliki kelemahan: berkencan dengan situasi intensif menjaga konsistensi dan sinkronisasi menjadi tantangan nyata. Basis data mungkin menjadi hambatan atau berakhir di kondisi balapan dan menderita karena ketidakpastian.

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 1: Skenario perpecahan negara yang umum terlihat sebelum transisi ke
Aliran Kafka dan Kafka: agen mengomunikasikan pandangan mereka melalui API, status yang diperbarui dihitung melalui database pusat

Perkenalkan Kafka Streams, yang memudahkan pembuatan layanan mikro negara bersama

Sekitar setahun yang lalu, kami memutuskan untuk mencermati skenario negara bagian untuk mengatasi masalah ini. Kami segera memutuskan untuk mencoba Kafka Streams - kami tahu betapa terukur, sangat tersedia, dan toleran terhadap kesalahan, betapa kayanya fungsionalitas streaming yang dimilikinya (transformasi, termasuk yang stateful). Ini adalah hal yang kami perlukan, belum lagi betapa matang dan andalnya sistem pesan di Kafka.

Setiap layanan mikro stateful yang kami buat dibangun di atas instance Kafka Streams dengan topologi yang cukup sederhana. Ini terdiri dari 1) sumber 2) prosesor dengan penyimpanan nilai kunci yang persisten 3) sink:

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 2: Topologi default instans streaming kami untuk layanan mikro stateful. Perhatikan bahwa ada juga repositori di sini yang berisi metadata perencanaan.

Dalam pendekatan baru ini, agen menyusun pesan yang dimasukkan ke dalam topik sumber, dan konsumen—misalnya, layanan pemberitahuan email—menerima status bersama yang dihitung melalui sink (topik keluaran).

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 3: Contoh alur tugas baru untuk skenario dengan layanan mikro bersama: 1) agen menghasilkan pesan yang masuk ke topik sumber Kafka; 2) layanan mikro dengan status bersama (menggunakan Kafka Streams) memprosesnya dan menulis status terhitung ke topik akhir Kafka; setelah itu 3) konsumen menerima keadaan baru

Hai, penyimpanan nilai kunci bawaan ini sebenarnya sangat berguna!

Seperti disebutkan di atas, topologi negara bersama kami berisi penyimpanan nilai kunci. Kami menemukan beberapa opsi untuk menggunakannya, dan dua di antaranya dijelaskan di bawah.

Opsi #1: Gunakan penyimpanan nilai kunci untuk perhitungan

Penyimpanan nilai kunci pertama kami berisi data tambahan yang kami butuhkan untuk penghitungan. Misalnya, dalam beberapa kasus, pembagian negara bagian ditentukan berdasarkan prinsip "suara mayoritas". Repositori dapat menyimpan semua laporan agen terbaru mengenai status beberapa objek. Kemudian, ketika kami menerima laporan baru dari satu agen atau lainnya, kami dapat menyimpannya, mengambil laporan dari semua agen lain tentang keadaan objek yang sama dari penyimpanan, dan mengulangi penghitungan.
Gambar 4 di bawah menunjukkan bagaimana kita mengekspos penyimpanan kunci/nilai ke metode pemrosesan prosesor sehingga pesan baru kemudian dapat diproses.

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Ilustrasi 4: Kami membuka akses ke penyimpanan nilai kunci untuk metode pemrosesan prosesor (setelah ini, setiap skrip yang bekerja dengan status bersama harus mengimplementasikan metode tersebut doProcess)

Opsi #2: Membuat CRUD API di atas Kafka Streams

Setelah menetapkan alur tugas dasar, kami mulai mencoba menulis RESTful CRUD API untuk layanan mikro negara bagian kami. Kami ingin dapat mengambil status beberapa atau semua objek, serta mengatur atau menghapus status suatu objek (berguna untuk dukungan backend).

Untuk mendukung semua Get State API, kapan pun kami perlu menghitung ulang status selama pemrosesan, kami menyimpannya di penyimpanan nilai kunci bawaan untuk waktu yang lama. Dalam hal ini, mengimplementasikan API tersebut menjadi cukup mudah menggunakan satu instance Kafka Streams, seperti yang ditunjukkan dalam daftar di bawah:

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 5: Menggunakan penyimpanan nilai kunci bawaan untuk mendapatkan status objek yang telah dihitung sebelumnya

Memperbarui keadaan suatu objek melalui API juga mudah diterapkan. Pada dasarnya, yang perlu Anda lakukan hanyalah membuat produser Kafka dan menggunakannya untuk membuat rekaman yang berisi status baru. Hal ini memastikan bahwa semua pesan yang dihasilkan melalui API akan diproses dengan cara yang sama seperti yang diterima dari produsen lain (misalnya agen).

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 6: Anda dapat mengatur status suatu objek menggunakan produser Kafka

Komplikasi kecil: Kafka memiliki banyak partisi

Selanjutnya, kami ingin mendistribusikan beban pemrosesan dan meningkatkan ketersediaan dengan menyediakan cluster layanan mikro negara bersama per skenario. Penyiapannya sangat mudah: setelah kami mengonfigurasi semua instance agar berjalan di bawah ID aplikasi yang sama (dan server bootstrap yang sama), hampir semua hal lainnya dilakukan secara otomatis. Kami juga menetapkan bahwa setiap topik sumber akan terdiri dari beberapa partisi, sehingga setiap instance dapat diberi subset dari partisi tersebut.

Saya juga akan menyebutkan bahwa merupakan praktik umum untuk membuat salinan cadangan dari penyimpanan negara sehingga, misalnya, jika terjadi pemulihan setelah kegagalan, transfer salinan ini ke instance lain. Untuk setiap penyimpanan negara bagian di Kafka Streams, topik yang direplikasi dibuat dengan log perubahan (yang melacak pembaruan lokal). Oleh karena itu, Kafka terus-menerus mencadangkan toko negara. Oleh karena itu, jika terjadi kegagalan pada satu atau beberapa instans Kafka Streams, penyimpanan status dapat dengan cepat dipulihkan pada instans lain, tempat partisi terkait akan dipindahkan. Pengujian kami menunjukkan bahwa hal ini dilakukan dalam hitungan detik, meskipun terdapat jutaan rekaman di penyimpanan.

Beralih dari satu layanan mikro dengan status bersama ke sekelompok layanan mikro, mengimplementasikan Get State API menjadi lebih mudah. Dalam situasi baru, penyimpanan negara dari setiap layanan mikro hanya berisi sebagian dari gambaran keseluruhan (objek yang kuncinya dipetakan ke partisi tertentu). Kami harus menentukan instance mana yang berisi status objek yang kami perlukan, dan kami melakukan ini berdasarkan metadata thread, seperti yang ditunjukkan di bawah ini:

Tidak hanya memproses: Bagaimana kami membuat database terdistribusi dari Kafka Streams, dan apa hasilnya

Gambar 7: Dengan menggunakan metadata aliran, kami menentukan instance mana yang akan menanyakan status objek yang diinginkan; pendekatan serupa digunakan dengan GET ALL API

Temuan Kunci

Penyimpanan negara di Kafka Streams dapat berfungsi sebagai database terdistribusi secara de facto,

  • terus-menerus direplikasi di Kafka
  • CRUD API dapat dengan mudah dibangun di atas sistem seperti itu
  • Menangani banyak partisi sedikit lebih rumit
  • Dimungkinkan juga untuk menambahkan satu atau lebih penyimpanan negara ke topologi streaming untuk menyimpan data tambahan. Opsi ini dapat digunakan untuk:
  • Penyimpanan data jangka panjang diperlukan untuk penghitungan selama pemrosesan aliran
  • Penyimpanan data jangka panjang yang mungkin berguna saat instans streaming disediakan lagi
  • lebih banyak...

Keunggulan ini dan keunggulan lainnya membuat Kafka Streams sangat cocok untuk mempertahankan keadaan global dalam sistem terdistribusi seperti milik kita. Kafka Streams telah terbukti sangat andal dalam produksi (hampir tidak ada pesan yang hilang sejak penerapannya), dan kami yakin kemampuannya tidak akan berhenti di situ!

Sumber: www.habr.com

Tambah komentar