Mendesain Event-Driven Architecture — Part 2

Apa Kafka Itu Sebenarnya?

D. Husni Fahri Rizal
The Legend
17 min readJul 25, 2021

--

Memahami Kafka bagi sebagian orang sama seperti memahami gajah oleh orang yang memiliki kekurangan dalam penglihatan. Gajah dipahami seperti tali atau tambang jika yang dipegang adalah ekornya, gajah dipahami seperti pohon jika yang dipegang adalah kakinya, dan gajah mungkin dipahami seperti ular yang mendesis ketika yang dipegang adalah belalainya.

Seperti itu lah jika pendekatan yang digunakan berbeda, maka Kafka dapat diidentifikasi dengan cara yang berbeda tergantung sudut pandang kita dalam mendekatinya. Berikut dijelaskan beberapa pemahaman Kafka dari sudut pandang kebanyakan orang.

Sejarah Kafka

Apache Kafka pertama kali dikembangkan oleh Jay Kreps, Neha Narkhede, dan Jun Rao di LinkedIn pada tahun 2010 sebagai sebuah sistem messaging yang dirancang untuk mengatasi masalah skala besar pada platform LinkedIn. Mereka merasa bahwa sistem messaging yang ada saat itu kurang mampu mengatasi kebutuhan scale LinkedIn yang terus berkembang.

Setelah berhasil digunakan di LinkedIn, Apache Kafka diusulkan untuk dijadikan sebuah proyek open-source di Apache Software Foundation pada tahun 2011 dan berhasil menjadi bagian dari Apache Incubator pada bulan Maret 2011. Pada awalnya Kafka masih fokus pada pengolahan data secara streaming dengan tujuan untuk meningkatkan efisiensi dan throughput pada platform LinkedIn.

Namun, seiring perkembangan dan penggunaan Kafka yang semakin meluas, Apache Kafka kemudian mengalami evolusi dan menawarkan fitur-fitur baru seperti pengolahan data real-time dan juga dukungan untuk sistem transaksional. Pada tahun 2012, Kafka resmi menjadi bagian dari Apache Top Level Project dan terus dikembangkan hingga saat ini.

Saat ini, Apache Kafka digunakan oleh banyak perusahaan besar di seluruh dunia seperti LinkedIn, Netflix, Uber, Airbnb, dan masih banyak lagi. Apache Kafka juga telah menjadi salah satu teknologi paling populer di bidang pengolahan data dan streaming.

Kafka itu adalah REST tetapi Asynchronous?

Kafka menyediakan protokol asynchronous untuk menghubungkan beberapa software program sehingga dapat saling terhubung. Walaupun begitu, Kafka memiliki perbedaan dengan TCP, HTTP, atau RCP protocol.

Pada Kafka, terdapat Broker yang berada di dalam infrastruktur dan dapat mem-broadcast message ke setiap software program yang membutuhkan. Selain itu, Broker juga dapat menyimpan message dalam kurun waktu tertentu. Oleh karena itu, Kafka cocok untuk digunakan dalam proses streaming atau pengiriman message dengan metode fire and forget.

Salah satu contoh penggunaan Kafka adalah untuk request-response secara asynchronous. Misalnya, kita dapat melakukan panggilan getCustomer() dan memberikan CustomerId melalui publisher. Kemudian, di bagian consumer akan dilakukan query menggunakan customer id tersebut, dan hasilnya akan dikirimkan kembali ke publisher yang membutuhkannya sebagai replay. Dengan cara ini, data customer dapat diakses secara asynchronous melalui Kafka.

Kita dapat menggunakan Kafka untuk membuat request-response dengan menggunakan dua topic. Terkadang, sistem dibuat dengan cara seperti ini tanpa memanfaatkan Broker lebih banyak, seperti tidak membutuhkan broadcast dan penyimpanan. Namun, jika hanya menggunakan pendekatan ini, terkadang lebih mudah menggunakan HTTP daripada Kafka. Lalu, mengapa kita harus menggunakan Kafka.

Kafka itu Seperti Database?

Mungkin ada sebagian orang yang membandingkan Kafka dengan database. Topic pada Kafka dengan ukuran terabytes terkadang dapat disimpan di dalam Kafka. Kafka memiliki antarmuka SQL yang memungkinkan pengguna untuk melakukan pencarian dan membuat tampilan data (view). Selain itu, Kafka kini telah mendukung transaksi seperti halnya database tradisional.

Kafka memiliki banyak fitur yang mirip dengan database tradisional. Namun, Kafka juga memiliki kelebihan-kelebihan yang membuatnya unik. Beberapa kelebihannya antara lain adalah adanya kemmapuan untuk menyimpan data, memproses data secara real-time, dan membuat tampilan data (view).

Kafka tidak sepenuhnya dapat dianggap sebagai database, karena fokus utamanya adalah pada pemindahan data dan pengolahan data secara real-time, bukan penyimpanan data. Dengan demikian, Kafka lebih tepat dianggap sebagai platform untuk memproses dan mengoperasikan data secara real-time.

Kafka itu Service Bus (ESB)?

Jika kita memahami Kafka sebagai sistem messaging yang memiliki antarmuka koneksi, dapat melakukan pengambilan dan pengiriman data ke berbagai antarmuka dan datastore, serta sebagai API streaming yang dapat memanipulasi data di tengah perjalanan, maka Kafka dapat dianggap sebagai Enterprise Service Bus (ESB).

Sebenarnya hampir sama, tetapi Kafka difokuskan pada integrasi sistem lama dengan sistem baru menggunakan messaging yang memiliki low latency dalam hal request-response. Oleh karena itu, Kafka dapat dianggap sebagai EASB yang siap pakai.

Kafka sebenarnya adalah Platform Streaming yang menekankan pada throughput yang tinggi dan pemrosesan data streaming secara real-time. Kafka cluster adalah sistem terdistribusi yang memiliki kemampuan utama untuk memberikan tingkat availability yang tinggi, penyimpanan data, dan scale-out linear.

Kafka dilengkapi dengan tool seperti Kafka Streams dan KSQL yang memberikan kemampuan untuk memanipulasi event yang masuk. Dengan demikian, Kafka memberikan kemampuan pemrosesan data yang tersedia di lapisan aplikasi melalui API yang dimilikinya. Walaupun demikian, Kafka berbeda dengan ESB karena lebih menekankan pada throughput yang tinggi, ketersediaan, penyimpanan, dan skala-out linear sebagai sebuah platform streaming.

https://softjourn.com/insights/do-esb-s-still-play-a-role

Kafka Adalah Streaming Platform

Berdasarkan penjelasan yang telah dijelaskan di atas, Kafka dapat dikategorikan sebagai Streaming Platform yang memiliki core terdiri dari cluster dan broker-broker Kafka. Kafka menyediakan berbagai API untuk berinteraksi dengan broker-broker ini yang tersedia untuk berbagai bahasa pemrograman seperti GO, JAVA, Scala, Python, REST dan lain-lain.

Sebagai platform streaming, Kafka menggabungkan berbagai tool dengan tujuan mengubah data yang statis menjadi data yang mengalir (streaming). Kita dapat menganalogikan Kafka sebagai “pusat saraf” dari sistem yang terdiri dari berbagai komponen yang terhubung melalui aliran data (stream).

Kemampuan broker untuk melakukan scaling, penyimpanan data yang handal, dan dapat berjalan tanpa hambatan membuat Kafka menjadi alat yang unik untuk menghubungkan berbagai aplikasi dan layanan yang berbeda di seluruh departemen atau organisasi. Interface Connect (Kafka Connect) memudahkan sistem-sistem legacy untuk terintegrasi dengan Kafka sehingga data dapat mengalir melalui Kafka dan dapat ditransfer ke sistem lainnya untuk penggunaan dan pemrosesan data lebih lanjut secara streaming.

Beberapa contoh penggunaan Kafka sebagai streaming platform dapat di baca di artikel :

  1. https://medium.com/the-legend/kafka-connect-dan-debezium-4e9b44f3179
  2. https://medium.com/the-legend/debezium-94e9b68580c9.

Bagian-Bagian Kafka

Kafka sebagai sebuah sistem tidak berdiri sendiri, tetapi terdiri dari beberapa bagian infrastruktur yang saling berkerjasama dan mendukung satu sama lain. Minimal untuk menjalankan Kafka cluster, harus memiliki bagian-bagian berikut:

  1. Kafka brokers: adalah server yang menjalankan Kafka. Setiap broker bertanggung jawab untuk menyimpan dan mengelola sejumlah partisi topik.
  2. ZooKeeper: adalah sistem koordinasi terdistribusi yang digunakan untuk mengelola broker Kafka. ZooKeeper bertanggung jawab untuk melacak status broker, topik, partisi, dan konsumen dalam cluster.
  3. Producer: adalah aplikasi atau sistem yang menghasilkan data ke Kafka. Producer menulis data ke salah satu atau beberapa partisi topik di broker.
  4. Consumer: adalah aplikasi atau sistem yang membaca data dari Kafka. Consumer membaca data dari partisi topik di broker.

Kita jelaskan lebih detil satu persatu bagian-bagian Kafka sebagai berikut.

Kafka Broker

Sebuah Kafka cluster terdiri dari satu atau lebih Kafka broker, yang bertanggung jawab untuk mengelola semua proses dari client. Broker bertanggung jawab untuk menerima input data dari producer, menyimpan data, dan meneruskan data ke consumer. Dalam sebuah Kafka cluster, broker bekerja secara terdistribusi untuk menyeimbangkan beban kerja dan meningkatkan ketersediaan sistem.

Zookeeper

Apache zookeeper digunakan oleh Kafka cluster untuk memelihara informasi, konfigurasi, dan semua kondisi serta status dari cluster (brokers, topic, dan user) secara terpusat.

Setiap Kafka cluster akan memiliki beberapa Zookeeper yang bekerja secara terdistribusi dan terkoordinasi satu sama lain. Direkomendasikan untuk memiliki jumlah Zookeeper yang ganjil, seperti 3 atau 5, untuk mencegah terjadinya Brain Split Problem. Anda dapat membaca contoh masalah Brain Split pada infrastruktur lain di artikel berikut ini:

https://medium.com/the-legend/elasticsearch-split-brain-problem-ec97f21f7a2c.

Kafka Topic

Kafka topic merupakan tempat di mana Kafka cluster menyimpan semua pesan yang dipublikasikan. Aplikasi atau perangkat lunak yang memproduksi pesan akan menyimpannya pada topik ini, sementara aplikasi konsumen akan membaca atau menerima pesan dari topik ini. Semua pesan akan dicatat pada topik selama kurun waktu tertentu dan dapat dikonfigurasi berapa lama data tersebut akan disimpan.

Kafka menyimpan catatan (record) dalam sebuah log (disebut juga sebagai “topic partition”), dan membuat konsumen bertanggung jawab untuk melacak posisi di dalam log tersebut dengan menggunakan “offset”. Konsumen biasanya maju ke offset yang lebih tinggi secara linier saat pesan dibaca, namun posisi sebenarnya dikendalikan oleh konsumen itu sendiri dan dapat dikonsumsi dalam urutan apa pun yang diinginkan. Hal ini memungkinkan konsumen untuk mengatur ulang offset ke posisi sebelumnya dan memproses ulang catatan jika dibutuhkan.

Topik Kafka dibagi menjadi beberapa partisi, yang masing-masing berisi catatan dalam urutan yang tidak dapat diubah. Setiap catatan dalam partisi ditentukan dan diidentifikasi oleh offset uniknya. Sebuah topik dapat memiliki beberapa partisi log. Hal ini memungkinkan banyak konsumen untuk membaca dari topik secara paralel. Partisi memungkinkan topik untuk diparalelkan dengan membagi data menjadi partisi tertentu di beberapa broker.

Dalam Kafka, replikasi diterapkan pada tingkat partisi. Unit tambahan dari partisi topik disebut sebagai replika. Setiap partisi umumnya memiliki beberapa replika yang berarti bahwa setiap pesan dalam partisi direplikasi melalui beberapa broker Kafka di dalam cluster.

Setiap partisi pada Kafka memiliki satu server yang bertindak sebagai leader dan sisanya sebagai follower. Leader partition menangani semua permintaan baca-tulis untuk partisi tertentu dan follower mereplikasi data dari leader. Jika server leader mengalami kegagalan, salah satu server follower akan menjadi leader secara otomatis. Penting untuk menjaga keseimbangan leader partition agar setiap broker menjadi leader dengan jumlah partisi yang seimbang untuk mendistribusikan beban secara merata.

Kafka Producer

Secara konseptual, produsen Kafka lebih sederhana daripada konsumen karena tidak memerlukan koordinasi kelompok. Seorang produsen menggunakan partitioner untuk memetakan setiap pesan ke partisi topik, dan mengirimkan permintaan produksi ke pemimpin partisi itu. Kafka menjamin bahwa semua pesan dengan kunci yang sama akan dikirimkan ke partisi yang sama.

Dengan demikian, biasanya produsen Kafka dianggap sebagai bagian yang lebih sederhana karena tidak memerlukan logika yang kompleks. Tugas utamanya hanya menerbitkan pesan ke topik. Producer Kafka itu bodoh.

Ketika sebuah produsen Kafka mempublikasikan sebuah rekaman data ke suatu topik, data tersebut akan diterbitkan ke pemimpin partisi topik. Pemimpin partisi akan menambahkan catatan ke dalam log dan menambahkan offset untuk catatan tersebut. Kafka hanya akan menampilkan catatan ke konsumen setelah catatan tersebut di-commit, dan setiap bagian dari data yang masuk akan ditumpuk di dalam cluster.

Produser harus mengetahui ke partisi mana data harus ditulis, dan hal ini tidak bergantung pada broker. Produser dapat melampirkan kunci ke data record yang memaksa data record tertentu harus ditulis ke partisi tertentu.

Semua data record dengan kunci yang sama akan tiba di partisi yang sama. Ini digunakan untuk memastikan bahwa urutan proses dapat dijamin ketika data dikonsumsi oleh konsumen. Memastikan urutan proses data yang masuk secara asinkron sangat penting untuk beberapa kasus penggunaan.

Jika kunci disediakan, maka partisi akan meng-hash kunci tersebut dengan algoritma murmur2 dan membaginya dengan jumlah partisi. Hasilnya adalah bahwa kunci yang sama selalu ditempatkan pada partisi yang sama. Namun, jika kunci tidak disediakan, perilaku akan tergantung pada versi Kafka yang digunakan.

Kesalahan umum saat menerbitkan rekaman adalah menetapkan kunci yang sama atau kunci nol untuk semua rekaman, yang mengakibatkan semua rekaman berakhir di partisi yang sama dan membuat topik menjadi tidak seimbang.

Konfigurasi Produser Kafka

Daftar lengkap pengaturan konfigurasi tersedia di Producer Configurations . Pengaturan konfigurasi utama dan bagaimana pengaruhnya terhadap perilaku produser dapat dijelaskan sebagai berikut.

  1. Konfigurasi Utama. Anda diharuskan untuk mengatur bootstrap.serversproperti agar produser dapat menemukan cluster Kafka.Meskipun tidak wajib, sebaiknya Anda selalu menetapkan client.idkarena hal ini memudahkan Anda dalam menghubungkan permintaan pada broker dengan instance klien yang membuatnya. Pengaturan ini sama untuk klien Java, C/C++, Python, Go, dan .NET.
  2. Message Durability. Anda dapat mengontrol durabilitas pesan yang ditulis ke Kafka melalui pengaturan acks. Nilai default dari acks adalah 1, yang mengharuskan pemimpin partisi memberikan konfirmasi bahwa penulisan berhasil. Jaminan terkuat yang disediakan oleh Kafka adalah dengan acks=all yang menjamin bahwa pemimpin partisi tidak hanya menerima penulisan, tetapi juga berhasil direplikasi ke semua replika yang sinkron. Anda juga dapat menggunakan nilai 0 untuk memaksimalkan throughput, tetapi ini akan mengurangi jaminan bahwa pesan berhasil ditulis ke log broker karena broker tidak akan mengirim respons dalam kasus ini. Ini juga berarti bahwa Anda tidak akan dapat menentukan offset pesan. Perlu dicatat bahwa untuk klien C/C++, Python, Go, dan .NET, ini adalah konfigurasi per topik, tetapi dapat diterapkan secara global menggunakan default_topic_conf di C/C++ dan default.topic.config di Python, Go, dan .NET.
  3. Message Ordering. Secara umum, pesan ditulis ke broker dalam urutan yang sama dengan yang diterima oleh klien produsen. Namun, jika Anda mengaktifkan percobaan ulang pesan dengan menyetel retrieske nilai yang lebih besar dari 0(yang merupakan default), maka pemesanan ulang pesan dapat terjadi karena percobaan ulang dapat terjadi setelah penulisan berikut berhasil. Untuk mengaktifkan retries tanpa penataan, Anda dapat mengatur max.in.flight.requests.per.connection = 1untuk memastikan bahwa hanya satu permintaan dapat dikirim ke broker pada suatu waktu. Tanpa percobaan ulang diaktifkan, broker akan mempertahankan urutan penulisan yang diterimanya, tetapi mungkin ada celah kekurangan karena kegagalan pengiriman tiap masing-masing pesan.
  4. Queuing Limit. Gunakan buffer.memoryuntuk membatasi total memori yang tersedia untuk klien Java untuk mengumpulkan pesan yang tidak terkirim. Ketika batas ini tercapai, produser akan memblokir pengiriman tambahan selama max.block.mssebelum menaikkan pengecualian. Selain itu, untuk menghindari menyimpan record dalam antrian tanpa batas waktu, Anda dapat mengatur batas waktu menggunakan request.timeout.ms. Jika batas waktu ini kedaluwarsa sebelum pesan berhasil dikirim, maka itu akan dihapus dari antrian dan pengecualian akan dilemparkan. Klien C/C++, Python, Go, dan .NET memiliki pengaturan yang serupa. Gunakan queue.buffering.max.messages untuk membatasi jumlah total pesan yang dapat diantrekan (untuk pengiriman, percobaan ulang, atau laporan pengiriman) pada waktu tertentu. queue.buffering.max.msmembatasi jumlah waktu klien menunggu untuk mengisi batch sebelum mengirimkannya ke broker.
  5. Batching and Compression. Produsen Kafka berusaha mengumpulkan pesan yang dikirim ke dalam batch untuk meningkatkan throughput. Dengan klien Java, Anda dapat menggunakan batch.sizeuntuk mengontrol ukuran maksimum dalam byte dari setiap kumpulan pesan. Untuk memberi lebih banyak waktu agar batch terisi, Anda dapat menggunakan linger.msagar produser menunda pengiriman. Kompresi dapat diaktifkan dengan compression.typepengaturan. Kompresi mencakup kumpulan pesan penuh, jadi kumpulan yang lebih besar biasanya berarti rasio kompresi yang lebih tinggi. Dengan klien C/C++, Python, Go, dan .NET, Anda dapat menggunakan batch.num.messagesuntuk menetapkan batas jumlah pesan yang terdapat dalam setiap batch. Saat menggunakan kompresi cepat, Anda memerlukan akses tulis ke /tmpdirektori. Jika Anda tidak memiliki akses tulis ke /tmpdirektori karena disetel ke noexec, berikan jalur direktori untuk snappy yang Anda miliki akses tulisnya.

Kafka Consumer

Kelompok consumer adalah sekumpulan consumer yang bekerja sama untuk mengkonsumsi data dari beberapa topik. Partisi dari semua topik dibagi di antara konsumen dalam grup. Ketika anggota grup baru tiba dan anggota lama pergi, partisi tersebut ditetapkan kembali sehingga setiap anggota menerima bagian yang proporsional dari partisi tersebut. Ini dikenal sebagai penyeimbangan kembali grup.

Perlu diperhatikan dalam consumer Kafka ada istilah dengan consumer dan Consumer Group yang memiki pengertian dan pengaruh yang beda. Setiap cunsumer dengan consumer id yang sama akan hanya mendapat atau membaca satu kali. Walau banyak service tetapi jika satu consumer id maka hanya satu instance yang akan menerima data. Consumer ini kadang di sebut low level consumer. Sedangkan consumer group akan mengelompokkan jenis consumser. Jika consumer graoup beda maka semua akan dapat membaca data dari topik tadi. Consumer ini kadang disebut konsumer level tinggi.

Konfigurasi Konsumen Kafka

Daftar lengkap pengaturan konfigurasi tersedia di Konfigurasi Konsumen . Beberapa pengaturan konfigurasi utama dan bagaimana pengaruhnya terhadap perilaku konsumen disorot di bawah ini.

  1. Konfigurasi Utama. Satu-satunya pengaturan yang diperlukan adalah bootstrap.servers, tetapi Anda harus menetapkan a client.id karena ini memungkinkan Anda untuk dengan mudah menghubungkan permintaan pada broker dengan instance klien yang membuatnya. Biasanya, semua konsumen dalam grup yang sama akan berbagi ID klien yang sama untuk menerapkan kuota client.
  2. Group Konfigurasi. Anda harus selalu mengonfigurasi group.idkecuali Anda menggunakan API penugasan sederhana dan Anda tidak perlu menyimpan offset di Kafka.
  3. Session Time Out. Anda dapat mengontrol batas waktu sesi dengan mengganti session.timeout.msnilainya. Standarnya adalah 10 detik di klien C/C++ dan Java, tetapi Anda dapat menambah waktu untuk menghindari penyeimbangan ulang yang berlebihan, misalnya karena konektivitas jaringan yang buruk atau jeda GC yang lama. Kelemahan utama menggunakan waktu tunggu sesi yang lebih besar adalah bahwa koordinator akan membutuhkan waktu lebih lama untuk mendeteksi saat instans konsumen mogok, yang berarti juga akan memakan waktu lebih lama bagi konsumen lain dalam grup untuk mengambil alih partisinya. Untuk shutdown normal, bagaimanapun, konsumen mengirimkan permintaan eksplisit kepada koordinator untuk meninggalkan grup yang memicu penyeimbangan kembali segera.
  4. Waktu Rebalance. Setting lain yang mempengaruhi perilaku rebalance adalah heartbeat.interval.ms. Ini mengontrol seberapa sering konsumen akan mengirim detak jantung ke koordinator. Ini juga merupakan cara konsumen mendeteksi ketika penyeimbangan kembali diperlukan, sehingga interval detak jantung yang lebih rendah umumnya berarti penyeimbangan kembali yang lebih cepat. Pengaturan default adalah tiga detik. Untuk kelompok yang lebih besar, mungkin bijaksana untuk meningkatkan pengaturan ini. Properti lain yang dapat mempengaruhi rebalancing berlebihan adalah max.poll.interval.ms. Properti ini menentukan waktu maksimum yang diperbolehkan antara panggilan ke metode polling konsumen ( Consumemetode dalam .NET) sebelum proses konsumen dianggap gagal. Standarnya adalah 300 detik dan dapat ditingkatkan dengan aman jika aplikasi Anda membutuhkan lebih banyak waktu untuk memproses pesan. Jika Anda menggunakan konsumen Java, Anda juga dapat menyesuaikan max.poll.recordsuntuk menyetel jumlah catatan yang ditangani pada setiap iterasi loop.
Pada satu consumer group
Pada multiple consumer group

Management Offset

Setelah konsumen menerima penugasannya dari koordinator, konsumen harus menentukan posisi awal untuk setiap partisi yang ditugaskan. Saat grup pertama kali dibuat, sebelum pesan apa pun digunakan, posisinya diatur menurut kebijakan reset offset yang dapat dikonfigurasi ( auto.offset.reset). Biasanya, konsumsi dimulai pada offset paling awal atau offset terbaru.

Saat konsumen dalam grup membaca pesan dari partisi yang ditetapkan oleh koordinator, ia harus melakukan offset yang sesuai dengan pesan yang telah dibacanya. Jika konsumen mogok atau dimatikan, partisinya akan ditugaskan kembali ke anggota lain, yang akan mulai konsumsi dari offset komitmen terakhir dari setiap partisi. Jika konsumen crash sebelum offset telah dilakukan, maka konsumen yang mengambil alih partisi akan menggunakan kebijakan reset.

Kebijakan komitmen offset sangat penting untuk memberikan jaminan pengiriman pesan yang dibutuhkan oleh aplikasi Anda. Secara default, konsumen dikonfigurasi untuk menggunakan kebijakan komit otomatis, yang memicu komit pada interval periodik. Konsumen juga mendukung API komit yang dapat digunakan untuk manajemen offset manual. Manajemen offset yang benar sangat penting karena mempengaruhi semantik pengiriman .

Secara default, konsumen dikonfigurasi untuk melakukan offset otomatis. Menggunakan komit otomatis memberi Anda pengiriman “setidaknya sekali”: Kafka menjamin bahwa tidak ada pesan yang terlewatkan, tetapi duplikat dimungkinkan. Komit otomatis pada dasarnya berfungsi sebagai cron dengan periode yang ditetapkan melalui auto.commit.interval.msproperti konfigurasi. Jika konsumen crash, maka setelah restart atau rebalance, posisi semua partisi yang dimiliki oleh konsumen yang crash akan diatur ulang ke offset commit terakhir. Ketika ini terjadi, posisi commit terakhir mungkin setua interval auto-commit itu sendiri. Setiap pesan yang telah tiba sejak komit terakhir harus dibaca lagi.

Jelas jika Anda ingin mengurangi jendela untuk duplikat, Anda dapat mengurangi interval komit otomatis, tetapi beberapa pengguna mungkin menginginkan kontrol yang lebih baik atas offset. Oleh karena itu konsumen mendukung API komit yang memberi Anda kendali penuh atas offset. Perhatikan bahwa ketika Anda menggunakan API komit secara langsung, Anda harus terlebih dahulu menonaktifkan komit otomatis dalam konfigurasi dengan menyetel enable.auto.commitproperti ke false.

Setiap panggilan ke API komit menghasilkan permintaan komit offset yang dikirim ke broker. Menggunakan API sinkron, konsumen diblokir hingga permintaan tersebut berhasil dikembalikan. Ini dapat mengurangi throughput keseluruhan karena konsumen mungkin dapat memproses catatan saat komit itu tertunda.

Salah satu cara untuk mengatasinya adalah dengan meningkatkan jumlah data yang dikembalikan saat polling. Konsumen memiliki setelan konfigurasi fetch.min.bytesyang mengontrol berapa banyak data yang dikembalikan dalam setiap pengambilan. Pialang akan menahan pengambilan sampai data yang cukup tersedia (atau fetch.max.wait.mskedaluwarsa). Tradeoff, bagaimanapun, adalah bahwa ini juga meningkatkan jumlah duplikat yang harus ditangani dalam kasus kegagalan terburuk.

Opsi kedua adalah menggunakan komit asinkron. Alih-alih menunggu permintaan selesai, konsumen dapat mengirim permintaan dan segera kembali menggunakan komitmen asinkron.

Jadi jika itu membantu kinerja, mengapa tidak selalu menggunakan async commit? Alasan utamanya adalah konsumen tidak mencoba kembali permintaan jika komit gagal. Ini adalah sesuatu yang melakukan secara serempak memberi Anda gratis; itu akan mencoba lagi tanpa batas sampai komit berhasil atau kesalahan yang tidak dapat dipulihkan ditemukan. Masalah dengan komit asinkron adalah berurusan dengan pemesanan komit. Pada saat konsumen mengetahui bahwa komit telah gagal, Anda mungkin sudah memproses kumpulan pesan berikutnya dan bahkan mengirim komit berikutnya. Dalam hal ini, percobaan ulang komit lama dapat menyebabkan konsumsi duplikat.

Alih-alih memperumit internal konsumen untuk mencoba dan menangani masalah ini dengan cara yang waras, API memberi Anda panggilan balik yang dipanggil saat komit berhasil atau gagal. Jika Anda suka, Anda dapat menggunakan panggilan balik ini untuk mencoba lagi komit, tetapi Anda harus menghadapi masalah penataan ulang yang sama.

Kegagalan komit offset hanya mengganggu jika komit berikut berhasil karena tidak akan benar-benar menghasilkan pembacaan duplikat. Namun, jika komit terakhir gagal sebelum penyeimbangan kembali terjadi atau sebelum konsumen dimatikan, maka offset akan diatur ulang ke komit terakhir dan Anda mungkin akan melihat duplikat. Oleh karena itu, pola umum adalah menggabungkan komit async di loop polling dengan komit sinkronisasi pada penyeimbangan ulang atau dimatikan. Berkomitmen pada penutupan itu mudah, tetapi Anda perlu cara untuk menghubungkan ke keseimbangan kembali.

Setiap rebalance memiliki dua fase: pencabutan partisi dan penetapan partisi. Metode pencabutan selalu dipanggil sebelum penyeimbangan ulang dan merupakan kesempatan terakhir untuk melakukan offset sebelum partisi ditetapkan kembali. Metode penugasan selalu dipanggil setelah penyeimbangan ulang dan dapat digunakan untuk mengatur posisi awal dari partisi yang ditetapkan. Dalam hal ini, kait pencabutan digunakan untuk melakukan offset saat ini secara sinkron.

Secara umum, komit asinkron harus dianggap kurang aman daripada komit sinkron. Kegagalan komit berturut-turut sebelum crash akan menghasilkan peningkatan pemrosesan duplikat. Anda dapat mengurangi bahaya ini dengan menambahkan logika untuk menangani kegagalan komit dalam panggilan balik atau dengan mencampur komit sinkron sesekali, tetapi Anda tidak boleh menambahkan terlalu banyak kerumitan kecuali pengujian menunjukkan itu perlu. Jika Anda membutuhkan lebih banyak keandalan, komit sinkron tersedia untuk Anda, dan Anda masih dapat meningkatkan dengan meningkatkan jumlah partisi topik dan jumlah konsumen dalam grup. Tetapi jika Anda hanya ingin memaksimalkan throughput dan Anda bersedia menerima beberapa peningkatan dalam jumlah duplikat, maka komit asinkron mungkin merupakan pilihan yang baik.

Poin yang agak jelas, tetapi satu yang layak untuk dibuat adalah bahwa komit asinkron hanya masuk akal untuk pengiriman pesan “setidaknya sekali”. Untuk mendapatkan “paling banyak sekali”, Anda perlu mengetahui apakah komit berhasil sebelum menggunakan pesan. Ini menyiratkan komit sinkron kecuali Anda memiliki kemampuan untuk “belum membaca” pesan setelah Anda menemukan bahwa komit gagal.

Dalam contoh, kami menunjukan beberapa contoh rinci dari API komit dan membahas pengorbanan dalam hal kinerja dan keandalan.

Saat menulis ke sistem eksternal, posisi konsumen harus dikoordinasikan dengan apa yang disimpan sebagai output. Itulah sebabnya konsumen menyimpan offsetnya di tempat yang sama dengan outputnya. Misalnya, konektor Kafka Connect mengisi data dalam HDFS bersama dengan offset data yang dibacanya sehingga dijamin bahwa data dan offset keduanya diperbarui, atau tidak keduanya. Pola serupa diikuti untuk banyak sistem data lain yang memerlukan semantik yang lebih kuat ini, dan yang pesannya tidak memiliki kunci utama untuk memungkinkan deduplikasi.

Beginilah cara Kafka mendukung pemrosesan tepat satu kali di Kafka Streams, dan produsen atau konsumen transaksional dapat digunakan secara umum untuk menyediakan pengiriman tepat satu kali saat mentransfer dan memproses data antara topik Kafka. Jika tidak, Kafka menjamin pengiriman setidaknya satu kali secara default, dan Anda dapat menerapkan pengiriman paling banyak satu kali dengan menonaktifkan percobaan ulang pada produsen dan melakukan offset pada konsumen sebelum memproses sekumpulan pesan.

Dua pengaturan utama yang mempengaruhi manajemen offset adalah apakah auto-commit diaktifkan dan kebijakan reset offset. Pertama, jika Anda mengatur enable.auto.commit(yang merupakan default), maka konsumen akan secara otomatis melakukan offset secara berkala pada interval yang ditetapkan oleh auto.commit.interval.ms. Standarnya adalah 5 detik.

Kedua, gunakan auto.offset.resetuntuk mendefinisikan perilaku konsumen saat tidak ada posisi komitmen (yang akan terjadi saat grup pertama kali diinisialisasi) atau saat offset berada di luar jangkauan. Anda dapat memilih untuk mengatur ulang posisi ke offset "paling awal" atau offset "terbaru" (default). Anda juga dapat memilih "tidak ada" jika Anda lebih suka mengatur offset awal sendiri dan Anda bersedia menangani kesalahan di luar jangkauan secara manual.

Apa Selanjutanya

Di atas adalah penjelasan apa itu Kafka sebenarnya. Di penjelasan selanjutnya kita akan membahas Core dari Kafka Streaming Plarform. Kita akan membahas lebih dalam mengenai Kafka Broker. Stay Tuned aja!

References

  1. Adam Bellemare. 2020. Building Event-Driven Microservices. USA: O’Reilly Media, Inc.
  2. Escoffier, Clement. 2017. Building Reactive Microservices in Java. USA: O’Reilly Media, Inc.
  3. Stopford, Ben. 2018. Designing Event-Driven System. USA: O’Reilly Media, Inc.
  4. Boner, Jonas. 2016. Reactive Microservice Architecture. USA: O’Reilly Media, Inc.

--

--

D. Husni Fahri Rizal
The Legend

Engineering Leader | Start-Up Advisor | Agile Coach | Microservices Expert | Professional Trainer | Investor Pemula