Replikasi antar broker di dalam satu cluster tidak melindungi data apabila seluruh cluster tidak tersedia, misalnya karena gangguan pada pusat data tempat cluster berdiri. Topik ini membahas replikasi data antar cluster menggunakan MirrorMaker 2, yaitu alat resmi Kafka untuk menyalin data antar cluster secara streaming. Bahasannya mencakup alasan menjalankan lebih dari satu cluster, topologi active-passive dan active-active, penamaan topic hasil replikasi, serta terjemahan offset untuk migrasi consumer. Setelah membaca topik ini, pilihan topologi dan isi konfigurasi MirrorMaker 2 untuk kebutuhan replikasi dapat ditentukan dengan dasar yang jelas.
Alasan menjalankan lebih dari satu cluster#
Alasan yang paling sering muncul adalah disaster recovery, yaitu menyiapkan cluster cadangan di pusat data lain sehingga apabila cluster utama tidak tersedia, aplikasi dapat dipindahkan ke cluster tersebut. Data di cluster cadangan diperbarui terus-menerus, sehingga selisih pesan saat gangguan terjadi hanya sebesar data yang belum selesai direplikasi. Persiapan semacam ini tidak dapat digantikan oleh replikasi antar broker karena kedua cluster berada di lokasi fisik yang berbeda.
Alasan lain berkaitan dengan lokasi data dan batasan organisasi. Aplikasi consumer yang berjalan dekat dengan pengguna membaca cluster yang dekat pula, sedangkan data tetap tersedia di cluster pusat. Aturan kepatuhan kadang mewajibkan data tertentu tidak meninggalkan wilayah tertentu, sehingga cluster per wilayah menjadi keharusan dan bukan pilihan. Kebutuhan lainnya berupa pemisahan fisik lingkungan produksi dan pengujian, pengumpulan data dari cluster terpencil ke satu cluster agregat, serta migrasi ke cloud yang berlangsung bertahap.
MirrorMaker 2 dan replication flow#
MirrorMaker 2, yang dirancang dalam KIP-382, dibangun di atas kerangka Kafka Connect dan menggantikan MirrorMaker versi lama. Alat ini mereplikasi topic beserta konfigurasinya, consumer group beserta offset-nya, dan ACL antar cluster. Penomoran partisi dipertahankan, topic baru dideteksi secara otomatis, dan prosesnya dapat diskalakan dengan menjalankan lebih dari satu MirrorMaker 2 sekaligus.
Satu aliran replikasi berarah disebut replication flow, yaitu aliran dari cluster sumber ke cluster tujuan yang dinyatakan dengan format {source}->{target} pada berkas konfigurasi. Cluster diberi alias, misalnya primary dan secondary, dan alias inilah yang digunakan di seluruh kunci konfigurasi. Setiap flow dijalankan oleh tiga connector, yaitu MirrorSourceConnector yang menyalin pesan, MirrorCheckpointConnector yang merekam offset grup consumer, dan MirrorHeartbeatConnector yang memeriksa konektivitas. Diagram berikut merangkum alur tersebut.
Berkas berikut memasang satu flow dari cluster primary ke cluster secondary dengan filter topic sensor-.* dan filter grup grup-.*. Konfigurasi MirrorMaker 2 berupa berkas properties, dan kunci yang sama dapat diatur secara umum maupun khusus untuk satu flow.
# konfigurasi MirrorMaker 2 untuk topologi active-passive
# alias cluster beserta alamat bootstrap masing-masing
clusters=primary, secondary
primary.bootstrap.servers=broker1-primary:9092
secondary.bootstrap.servers=broker1-secondary:9092
# replication flow satu arah dari primary ke secondary
primary->secondary.enabled=true
secondary->primary.enabled=false
# topic dan consumer group yang direplikasi, ditulis sebagai regular expression
primary->secondary.topics=sensor-.*
primary->secondary.groups=grup-.*
# tasks.max minimal 2 agar beban replikasi dapat terbagi ke lebih dari satu proses
tasks.max=2
# offset grup consumer disinkronkan langsung ke __consumer_offsets milik cluster target
primary->secondary.sync.group.offsets.enabled=truePerintah berikut menjalankan MirrorMaker 2 dengan berkas konfigurasi di atas. Eksekusi nyata membutuhkan dua cluster yang hidup sekaligus, sedangkan sandbox jalur ini hanya menjalankan satu broker, sehingga perintahnya tidak dieksekusi dan cukup dibaca sebagai pola.
# tidak-dijalankan
# jalankan MirrorMaker 2 dengan berkas konfigurasi yang sudah dibuat
cd /home/kal/my-project/kafka-runtime/kafka
bin/connect-mirror-maker.sh /home/kal/my-project/content/kafka/connect-dan-ekosistem/multi-cluster/mm2-pasang.propertiesTopologi active-passive dan active-active#
Topologi active-passive menjalankan satu cluster aktif yang menerima seluruh produksi dan satu cluster pasif yang hanya menerima salinan data. Konfigurasinya berupa satu flow satu arah, dan kunci flow searah balik dibiarkan false seperti pada berkas contoh di atas. Topologi ini menjadi pilihan utama untuk disaster recovery karena cluster pasif tidak menerima produksi langsung, sehingga tidak ada dua sumber kebenaran yang perlu diselaraskan. Pemulihannya berupa promosi cluster pasif menjadi cluster aktif, lalu aplikasi producer dan consumer diarahkan ke cluster tersebut.
Topologi active-active menjalankan dua cluster yang sama-sama menerima produksi dan saling mereplikasi, dengan dua flow yang dideklarasikan berlawanan arah pada berkas konfigurasi yang sama. Aplikasi membaca cluster yang paling dekat, sehingga latensi bagi pengguna di dua lokasi menjadi lebih rendah. Pesan yang sama pada kedua cluster tampil sebagai dua topic terpisah, yaitu topic lokal dan salinannya yang berprefiks alias, sehingga pencampuran data tidak terjadi. Perbandingan keduanya dirangkum dalam tabel berikut.
| Aspek | Active-passive | Active-active |
|---|---|---|
| Arah replication flow | satu arah, contohnya primary->secondary | dua arah, primary->secondary dan secondary->primary |
| Cluster yang menerima produksi | satu cluster aktif saja | dua cluster sekaligus |
| Topic di cluster lawan | salinan berprefiks alias | topic lokal tanpa prefiks dan salinan berprefiks alias |
| Tujuan utama | disaster recovery dengan cluster cadangan | kedekatan data bagi pengguna di dua lokasi |
| Pemulihan | promosi cluster pasif menjadi aktif | aplikasi pindah ke cluster yang masih hidup |
Penamaan topic remote dan deteksi siklus#
Topic hasil replikasi di cluster tujuan disebut topic remote, dan kebijakan penamaan bawaannya adalah {alias}.{topic} melalui DefaultReplicationPolicy. Topic sensor-suhu di cluster primary menjadi primary.sensor-suhu di cluster secondary, dengan jumlah partisi yang sama dan nomor partisi yang tetap. Jaminan ini membuat pesan tidak pernah digabung atau dipindah antar partisi saat replikasi, sehingga urutan di dalam partisi tetap terjaga. Consumer dapat berlangganan topic lokal saja, topic remote saja, atau keduanya sekaligus melalui langganan regular expression ketika data dari beberapa cluster perlu digabung di satu aplikasi.
Prefiks alias juga menjadi dasar deteksi siklus. Topic yang namanya sudah memuat alias primary tidak akan direplikasi kembali ke cluster primary, sehingga flow dua arah pada topologi active-active tidak menyalin pesan yang sama bolak-balik tanpa akhir. Aturan ini berlaku untuk topologi apa pun, dan alias yang sama tidak pernah muncul dua kali dalam satu nama topic, termasuk pada rantai replikasi panjang yang menghasilkan nama seperti us-west.us-east.topic1. MirrorHeartbeatConnector melengkapi mekanisme ini dengan topic heartbeat yang membuktikan cluster sumber masih terjangkau. Terakhir, producer hanya menulis topic lokal, sedangkan topic remote hanya ditulis oleh MirrorMaker 2, dan propagasi ACL pun menegakkan pembatasan tersebut.
Terjemahan offset dan checkpoint#
Offset grup consumer tersimpan di topic __consumer_offsets milik cluster tempat grup berjalan, sehingga consumer tidak dapat melanjutkan pekerjaan di cluster lain begitu saja. MirrorMaker 2 menjawab kebutuhan ini dengan dua mekanisme. Selama mereplikasi, MirrorSourceConnector merekam pasangan offset-sync, yaitu pasangan offset pada cluster sumber dan offset yang setara di topic remote. Selanjutnya MirrorCheckpointConnector menulis entri checkpoint untuk setiap grup consumer ke topic {alias}.checkpoints.internal di cluster target, misalnya primary.checkpoints.internal.
Entri checkpoint memuat nama grup, topic, partisi, upstream offset sebagai nilai commit terakhir di cluster sumber, dan downstream offset sebagai terjemahannya. Topic checkpoint ini terkompaksi sebagaimana __consumer_offsets, sehingga hanya nilai terakhir per grup yang tersimpan. Terjemahan menggunakan pasangan offset-sync yang terekam paling dekat sebelum nilai commit, karena tidak semua offset tercatat pada tabel sinkronisasi. Demo berikut menyimulasikan mekanisme tersebut dengan Python murni, yaitu dua commit grup grup-analitik diterjemahkan menggunakan tabel pasangan offset-sync, lalu checkpoint terakhirnya dicetak seperti isi topic checkpoint di cluster target.
# Simulasi terjemahan offset MirrorMaker 2 dengan Python murni. Pasangan
# offset-sync yang terekam saat replikasi digunakan untuk menerjemahkan offset
# yang dicommit consumer group di cluster source menjadi offset pada topic
# remote di cluster target, sebagaimana isi topic checkpoint milik MM2.
alias_source = "primary"
alias_target = "secondary"
topic = "sensor-suhu"
partisi = 0
topik_remote = f"{alias_source}.{topic}"
# pasangan offset-sync (upstream offset di cluster source, downstream offset
# yang setara di topic remote) yang terekam MirrorSourceConnector
offset_sync = [(0, 0), (3, 3), (7, 7)]
# riwayat commit grup-analitik pada topic di cluster source
riwayat_commit = [2, 6]
print(f"topic remote di {alias_target}: {topik_remote} partisi={partisi}")
print(f"offset-sync terekam: {offset_sync}")
for commit in riwayat_commit:
# checkpoint menggunakan pasangan offset-sync terakhir sebelum nilai commit
kandidat = [(u, d) for u, d in offset_sync if u <= commit]
up, down = max(kandidat)
print(f"commit {alias_source} offset={commit} -> upstream={up} downstream={down}")
# checkpoint terakhir dari riwayat commit menjadi titik lanjut baca saat failover
commit = riwayat_commit[-1]
kandidat = [(u, d) for u, d in offset_sync if u <= commit]
up, down = max(kandidat)
topik_checkpoint = f"{alias_source}.checkpoints.internal"
print(f"== isi topic {topik_checkpoint} di {alias_target} ==")
print(f"grup-analitik {topik_remote} partisi={partisi} upstream={up} downstream={down}")
print(f"failover: grup-analitik lanjut baca {topik_remote} dari offset={down}")topic remote di secondary: primary.sensor-suhu partisi=0
offset-sync terekam: [(0, 0), (3, 3), (7, 7)]
commit primary offset=2 -> upstream=0 downstream=0
commit primary offset=6 -> upstream=3 downstream=3
== isi topic primary.checkpoints.internal di secondary ==
grup-analitik primary.sensor-suhu partisi=0 upstream=3 downstream=3
failover: grup-analitik lanjut baca primary.sensor-suhu dari offset=3Keluaran memperlihatkan dua hal. Commit offset 2 diterjemahkan menjadi downstream offset 0 karena pasangan offset-sync (3, 3) belum terekam pada saat commit itu terjadi, sehingga titik lanjut baca berjalan dua pesan di belakang. Commit offset 6 memperoleh pasangan terdekat (3, 3) dan menghasilkan checkpoint upstream 3 dengan downstream 3, sehingga grup yang dipindahkan membaca ulang pesan beroffset 3 sampai 5. Kunci sync.group.offsets.enabled=true pada konfigurasi di atas membuat MirrorMaker 2 juga menulis hasil terjemahan ini langsung ke __consumer_offsets milik cluster target secara berkala, sehingga consumer di cluster target dengan nama grup yang sama langsung melanjutkan dari posisi tersebut.
Kesalahan umum#
Tiga kegagalan berikut paling sering muncul ketika replikasi antar cluster pertama kali dipasang. Setiap kegagalan dilengkapi penyebab dan perbaikannya.
Replikasi tidak berjalan padahal proses MirrorMaker 2 sudah hidup. Penyebabnya adalah flow belum diaktifkan, karena setiap flow bernilai false secara bawaan dan hanya clusters beserta alamat bootstrap yang otomatis dibaca. Perbaikannya berupa pengisian {source}->{target}.enabled=true untuk setiap arah yang diinginkan, kemudian proses MirrorMaker 2 dijalankan ulang karena perubahan konfigurasi hanya berlaku setelah proses berhenti dan hidup lagi.
Offset grup tidak terekam pada checkpoint. MirrorMaker 2 mengecualikan sekelompok nama grup secara bawaan melalui groups.exclude, yaitu console-consumer-.*, connect-.*, dan __.*, sehingga grup yang dibuat lewat kafka-console-consumer.sh untuk pengujian tidak pernah masuk checkpoint. Perbaikannya berupa penggunaan nama grup yang tidak terkena pola tersebut, atau penyesuaian groups.exclude selama masa pengujian dan pemulihannya setelah selesai.
Producer menulis ke topic remote di cluster target. Topic seperti primary.sensor-suhu hanya boleh ditulis oleh MirrorMaker 2, sedangkan produksi dari aplikasi tetap diarahkan ke topic lokal di cluster tempat aplikasi berjalan. Pelanggaran ini membuat dua sumber menulis ke satu topic, dan propagasi ACL pun menutup penulisan topic remote bagi pihak selain MirrorMaker 2. Perbaikannya berupa peninjauan alamat bootstrap pada konfigurasi producer agar menunjuk cluster yang benar.
Ringkasan#
- MirrorMaker 2 mereplikasi topic beserta konfigurasi, consumer group beserta offset, dan ACL antar cluster melalui replication flow berarah yang dinyatakan dengan alias
{source}->{target}pada berkas properties. - Topologi active-passive menjalankan satu flow satu arah untuk disaster recovery, sedangkan active-active menjalankan dua flow berlawanan arah dengan aplikasi yang membaca cluster terdekat.
- Topic hasil replikasi bernama
{alias}.{topic}dengan partisi yang tetap, dan prefiks alias sekaligus menjadi dasar deteksi siklus pada flow dua arah. - Terjemahan offset dijelaskan lewat pasangan offset-sync dan entri checkpoint pada topic
{alias}.checkpoints.internal, dengan penulisan langsung ke__consumer_offsetstarget bilasync.group.offsets.enableddiaktifkan.
Referensi#
- Geo-Replication (Cross-Cluster Data Mirroring) — Apache Kafka 4.4 Documentation — replication flow, penamaan topic remote, contoh topologi active-passive dan active-active, serta pemantauan replikasi.
- KIP-382: MirrorMaker 2.0 — Apache Kafka Wiki — desain MirrorMaker 2 berbasis Connect, topic offset-sync dan checkpoint, serta deteksi siklus.
- Apache Kafka Documentation — gerbang dokumentasi resmi Kafka yang memuat bagian geo-replication pada versi terkini.