Replication Factor #

Dalam arsitektur sistem terdistribusi modern, kegagalan infrastruktur fisik bukanlah masalah apakah akan terjadi, melainkan kapan ia akan terjadi. Hard disk akan rusak, switch jaringan akan mengalami malafungsi, dan pusat data dapat mengalami pemadaman listrik total. Untuk memastikan sistem tetap beroperasi dengan andal di tengah rentetan kegagalan tersebut, Apache Kafka mengandalkan mekanisme replikasi data. Komponen utama yang mengatur seberapa banyak salinan data yang kita miliki di seluruh kluster broker disebut Replication Factor (RF). Menentukan jumlah replika yang ideal merupakan salah satu keputusan perencanaan kapasitas (capacity planning) paling krusial karena berdampak langsung pada keandalan sistem, kapasitas penyimpanan disk, dan biaya infrastruktur jaringan kita.


Dasar-Dasar Replikasi dan Perhitungan Matematis Toleransi Kegagalan #

Replication Factor menentukan jumlah total salinan partisi topik yang disebarkan ke seluruh broker di dalam kluster Kafka. Salinan ini mencakup satu replika utama yang bertindak sebagai Leader (melayani operasi tulis dan baca secara default) dan sisanya sebagai Followers (menyalin data secara pasif dari leader).

Sebagai contoh, jika kita membuat topik dengan replication.factor=3, maka untuk setiap partisi di topik tersebut, akan ada 1 Leader partisi dan 2 Follower partisi yang tersebar di broker yang berbeda.

Formula Toleransi Kegagalan Broker #

Hubungan antara tingkat ketahanan data kita dengan jumlah replika dapat dirumuskan secara matematis. Toleransi kegagalan kluster kita bergantung pada konfigurasi parameter acks yang digunakan oleh produser serta nilai min.insync.replicas topik.

Skenario A: Menggunakan acks=1 atau acks=0 #

If produser tidak menuntut replikasi penuh sebelum mendapatkan ACK, maka ketersediaan data untuk dibaca (read availability) akan tetap terjaga selama minimal ada satu replika partisi yang masih hidup.

  • Toleransi Kegagalan Tulis & Baca:

$$\text{Toleransi Broker Crash} = R - 1$$

Di mana $R$ adalah nilai replication.factor. Dengan $R=3$, kita dapat mentolerir maksimal $2$ broker mati mendadak secara bersamaan tanpa kehilangan akses data.

Skenario B: Menggunakan acks=all (Durabilitas Tinggi) #

Jika produser menuntut konfirmasi dari seluruh anggota kuorum ISR sebelum menyatakan sukses, dan topik dikonfigurasi dengan batas minimum replika aktif min.insync.replicas = M, maka:

  • Toleransi Kegagalan Tulis (Write Availability):

$$\text{Toleransi Broker Crash} = R - M$$

Jika kita menyetel $R=3$ and $M=2$ (konfigurasi standar industri), maka:

$$\text{Toleransi} = 3 - 2 = 1\text{ Broker}$$

Jika hanya ada 1 broker yang mati, kluster tetap dapat menerima penulisan data baru karena sisa $2$ broker yang hidup masih memenuhi batas kuorum minimum $M$. Namun, jika $2$ broker mati sekaligus (sisa broker hidup tinggal 1), maka operasi penulisan dari produser akan langsung diblokir dan dibalas dengan error NotEnoughReplicasException, demi mencegah penulisan data yang tidak dapat direplikasi dengan aman.


Bagaimana Kafka Menentukan Penempatan Replika? (Assignment Algorithm) #

Ketika kita membuat topik baru, Kafka Controller secara otomatis menjalankan algoritma penempatan replika untuk mendistribusikan partisi secara adil di seluruh broker yang tersedia. Algoritma ini bertujuan untuk meratakan beban I/O disk dan jaringan.

Algoritma Penempatan Default (Tanpa Rack Awareness) #

Misalkan kita memiliki $N$ broker dan kita ingin menempatkan partisi $P$ dengan replication factor $R$:

  1. Memilih Broker Pertama untuk Leader: Kafka Controller mengurutkan daftar broker secara acak untuk inisialisasi awal. Untuk partisi ke-$i$, broker leader dipilih dengan rumus:

$$\text{Leader Broker} = i \pmod N$$

  1. Menyebarkan Replika Follower: Untuk replika ke-$j$ dari partisi tersebut (di mana $0 < j < R$), broker pengikut ditempatkan pada broker berikutnya secara berurutan dengan pergeseran (shifting):

$$\text{Follower Broker} = (i + j + \text{shift}) \pmod N$$

Di mana shift bertambah setiap kali daftar broker selesai dikitari sekali. Hal ini menjamin bahwa jika broker pertama sering menjadi leader untuk partisi bernomor genap, ia tidak akan kelebihan beban oleh replika follower partisi lainnya.


Arsitektur Rack Awareness (broker.rack) #

Menetapkan replication.factor=3 saja belum menjamin keamanan data jika seluruh broker kita berada di rak server fisik atau infrastruktur virtual (virtual hypervisor) yang sama. Jika rak server tersebut mengalami kegagalan pasokan daya listrik, seluruh replika data kita akan mati secara bersamaan.

Untuk mencegah skenario bencana ini, Kafka menyediakan fitur Rack Awareness.

flowchart TD
    subgraph DC ["Pusat Data Cloud (Region: ap-southeast-3)"]
        direction LR
        
        subgraph AZ_A ["Availability Zone A <br/>'(broker.rack=zone-a)'"]
            B1["Broker 1 <br/>Partisi 0 (Leader)"]
        end

        subgraph AZ_B ["Availability Zone B <br/>'(broker.rack=zone-b)'"]
            B2["Broker 2 <br/>Partisi 0 (Follower)"]
        end

        subgraph AZ_C ["Availability Zone C <br/>'(broker.rack=zone-c)'"]
            B3["Broker 3 <br/>Partisi 0 (Follower)"]
        end
    end

    B1 -. "Replikasi Lintas AZ" .-> B2
    B1 -. "Replikasi Lintas AZ" .-> B3
    style B1 stroke:#0288d1,stroke-width:2px
    style B2 stroke:#2e7d32,stroke-width:2px
    style B3 stroke:#2e7d32,stroke-width:2px

Bagaimana Rack Awareness Bekerja? #

  1. Kita mengonfigurasi properti broker.rack pada berkas konfigurasi setiap broker untuk mengidentifikasi lokasi fisiknya (misalnya, nama rak fisik di data center lokal, atau nama Availability Zone pada penyedia cloud seperti us-east-1a, us-east-1b, dst.).
  2. Ketika kita membuat topik baru, Controller Kafka akan membaca konfigurasi rak dari seluruh broker.
  3. Controller secara cerdas akan menyebarkan replika dari satu partisi yang sama ke broker-broker yang memiliki nilai broker.rack yang berbeda.
  4. Jaminan: Tidak akan ada dua replika dari partisi yang sama diletakkan di rak/zona yang sama, kecuali jumlah replika melebihi jumlah rak yang tersedia.

Dengan arsitektur ini, jika satu Availability Zone mengalami pemadaman listrik total secara massal, kluster Kafka kita dijamin tetap hidup dan konsisten karena replika cadangan berada di zona aman yang berbeda.


Analisis Biaya Jaringan Lintas Availability Zone (Cross-AZ Cost) #

Penyebaran replika lintas Availability Zone (AZ) adalah praktik wajib untuk keandalan tinggi, namun ada konsekuensi biaya finansial yang signifikan yang harus kita antisipasi secara cermat.

Penyedia cloud (seperti AWS, GCP, atau Azure) mengenakan biaya untuk setiap gigabyte data yang mengalir keluar (egress) dari satu AZ ke AZ lainnya di region yang sama (misalnya: $0.01 per GB).

Perhitungan Kasus Nyata #

Mari kita lakukan estimasi biaya lalu lintas jaringan untuk kluster produksi dengan spesifikasi berikut:

  • Throughput Produser: 500 MB/detik (setara dengan 1.8 TB/jam atau 43.2 TB/hari data bersih).
  • Replication Factor: 3 (terdistribusi di 3 AZ terpisah).
  • Biaya Jaringan Lintas AZ: $0.01 per GB ($10 per TB) untuk transfer data masuk dan keluar AZ.

Skenario 1: Tanpa Optimasi Follower Fetching (Pembacaan Klasik) #

  1. Lalu Lintas Replikasi: Pesan ditulis ke Broker Leader di AZ-A, kemudian ditarik oleh Follower 1 di AZ-B (43.2 TB/hari) dan Follower 2 di AZ-C (43.2 TB/hari). Total lalu lintas replikasi lintas AZ: 86.4 TB/hari.
  2. Lalu Lintas Konsumen: Jika konsumen kita dideploy secara acak (misal, 50% pembacaan berasal dari instans di AZ-B atau AZ-C yang membaca ke Leader di AZ-A), maka ada transfer data keluar tambahan sebesar:

$$43.2 \text{ TB/hari} \times 66.6% \approx 28.8 \text{ TB/hari}$$

  1. Total Biaya:
    • Total lalu lintas lintas AZ: $86.4 + 28.8 = 115.2 \text{ TB/hari}$.
    • Biaya harian: $115.2 \text{ TB} \times $10 = $1,152 \text{ per hari}$.
    • Biaya bulanan: $34,560 per bulan (~Rp518.000.000) hanya untuk biaya jaringan internal!

Skenario 2: Dengan Optimasi Follower Fetching #

Dengan mengaktifkan Follower Fetching, aplikasi konsumen di AZ-B hanya akan membaca dari Follower 1 di AZ-B (lokal AZ), dan konsumen di AZ-C membaca dari Follower 2 di AZ-C.

  • Lalu lintas replikasi lintas AZ tetap 86.4 TB/hari.
  • Lalu lintas konsumen lintas AZ berkurang menjadi 0 TB/hari (karena semua konsumen membaca secara lokal di AZ masing-masing).
  • Total Biaya Baru: $86.4 \text{ TB} \times $10 = $864 \text{ per hari}$ ($25,920 per bulan).
  • Penghematan Finansial: Kita menghemat $8,640 per bulan (~Rp130.000.000) hanya dengan satu perubahan konfigurasi sederhana.

Mekanisme Penulisan Log Fisik ke Disk: Page Cache vs fsync #

Tingkat durabilitas dari replication factor juga bergantung pada bagaimana broker menulis data ke media penyimpanan fisik (disk storage).

Secara default, ketika broker Kafka menerima pesan baru (baik leader dari produser maupun follower dari leader), broker hanya menulis data tersebut ke Page Cache sistem operasi (RAM) menggunakan system call standard JVM, tanpa memanggil instruksi fsync untuk memaksa penulisan langsung ke piringan disk fisik.

flowchart LR
    Producer["Klien Produser"] --> Socket["Socket Jaringan"] --> Cache["Page Cache OS Broker (RAM)"] --> ACK["Respon ACK"]

Mengapa Kafka Merekomendasikan Menolak Penggunaan fsync Sinkron? #

Banyak database tradisional memaksa fsync sinkron setelah setiap transaksi untuk menjamin keamanan. Di Kafka, kita dapat mengatur hal ini melalui properti log.flush.interval.messages dan log.flush.interval.ms. Namun, Kafka sangat menyarankan untuk membiarkan parameter tersebut pada nilai default-nya (tidak terbatas / menyerahkan sepenuhnya ke sistem operasi).

Alasan utamanya adalah:

  1. Penurunan Performa: Pemanggilan fsync sinkron akan mengubah operasi penulisan sequential memory yang sangat cepat menjadi operasi blocking disk I/O yang sangat lambat, menurunkan throughput Kafka hingga 90%.
  2. Keamanan Melalui Replikasi Lintas Broker: Kafka menggeser jaminan keamanan data dari tingkat single-node physical hardware ke tingkat multi-node active replication. Kehilangan daya pada satu broker tetap aman karena 2 broker lain memegang data yang sama di memori mereka. Kemungkinan 3 broker terpisah mengalami mati daya secara bersamaan sangatlah kecil (terutama jika menggunakan Rack Awareness).

Simulasi Langkah Demi Langkah Kegagalan dan Sinkronisasi Replikasi #

Mari kita simulasikan secara kronologis bagaimana kluster mengelola replikasi ketika terjadi gangguan fisik.

Fase 1: Gangguan Terjadi #

  1. Broker 1 (Leader Partisi 0) crash akibat kegagalan power supply.
  2. Kuorum Controller mendeteksi hilangnya detak jantung Broker 1.
  3. Controller menunjuk Broker 2 (Follower terlama di ISR) sebagai Leader baru. Leader Epoch naik dari 1 menjadi 2.
  4. Keanggotaan ISR untuk Partisi 0 menyusut menjadi: [2, 3].

Fase 2: Sinkronisasi Ulang Saat Pemulihan #

  1. Tim operasional mengganti komponen hardware Broker 1 dan menghidupkannya kembali.
  2. Broker 1 menyala dan mendaftar kembali ke Controller.
  3. Broker 1 menyadari ia bukan lagi leader. Ia mengirimkan OffsetsForLeaderEpochRequest ke Broker 2 untuk menanyakan offset akhir Epoch 1.
  4. Broker 2 membalas bahwa Epoch 1 berakhir di offset 10.000. Broker 1 memeriksa log miliknya sendiri dan mendeteksi bahwa ia memiliki data hingga offset 10.050 (ada 50 pesan yang sempat ditulis secara lokal sebelum crash tapi belum direplikasi).
  5. Broker 1 memotong log-nya kembali ke offset 10.000 untuk menyelaraskan diri, kemudian mulai menarik data dari Broker 2 mulai offset 10.001.
  6. Setelah LEO Broker 1 berhasil mengejar ketertinggalan dan berada dalam selisih waktu di bawah replica.lag.time.max.ms, Broker 1 secara otomatis dimasukkan kembali ke dalam kuorum ISR: [1, 2, 3].

Penyelarasan untuk Skenario Bencana Multi-Region (Disaster Recovery) #

Hingga saat ini, kita membahas replikasi di dalam satu kluster (intra-cluster replication). Untuk sistem dengan level toleransi kegagalan ekstra tinggi (seperti layanan perbankan inti), kita harus mengantisipasi kehancuran satu wilayah geografis penuh (region outage).

Untuk itu, kita harus menerapkan replikasi antar-kluster (inter-cluster replication) lintas region:

1. MirrorMaker 2 (MM2) #

MM2 adalah alat replikasi asinkron berbasis Kafka Connect yang membaca data dari kluster utama di Region-A dan mempublikasikannya kembali ke kluster cadangan di Region-B.

  • Kelemahan: Replikasi asinkron berarti ada latensi replikasi (RPO - Recovery Point Objective tidak bernilai nol, ada risiko kehilangan data beberapa detik terakhir jika Region-A hancur total).

2. Confluent Cluster Linking #

Teknologi modern yang memungkinkan replikasi langsung antar-broker lintas region tanpa memerlukan engine Kafka Connect eksternal. Replikasi dilakukan di tingkat protokol broker ke broker secara langsung, menjaga offset pesan tetap identik di kedua region secara dinamis (active-passive failover).


CLI Operasional: Membuat & Mengubah Replication Factor #

Berikut adalah instruksi baris perintah praktis untuk mengelola konfigurasi replikasi di tingkat produksi.

1. Membuat Topik Baru dengan Replication Factor Tertentu #

# Membuat topik pembayaran dengan 6 partisi dan replikasi 3
kafka-topics.sh --bootstrap-server localhost:9092 \
  --create \
  --topic payment-transactions \
  --partitions 6 \
  --replication-factor 3 \
  --config min.insync.replicas=2

2. Mengubah Replication Factor Topik yang Sudah Berjalan dengan Throttling #

Proses pemindahan replika yang besar dapat menyumbat jaringan kluster. Kita harus menerapkan batas bandwidth (throttling) selama proses migrasi berlangsung.

Langkah A: Buat File JSON Reassignment (reassignment.json) #

Buat berkas konfigurasi yang mendefinisikan pemetaan partisi baru ke broker target secara manual:

{
  "version": 1,
  "partitions": [
    {
      "topic": "customer-clicks",
      "partition": 0,
      "replicas": [1, 2, 3],
      "log_dirs": ["any", "any", "any"]
    }
  ]
}

Langkah B: Jalankan Reassign dengan Batasan Bandwidth (Throttle) #

Kita membatasi kecepatan replikasi data maksimum sebesar 50 MB/s (52.428.800 byte/s) agar tidak mengganggu lalu lintas data produser aktif:

# Jalankan perintah eksekusi dengan throttle 50MB/s
kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file reassignment.json \
  --throttle 52428800 \
  --execute

Langkah C: Verifikasi dan Pembersihan Throttle #

Setelah status verifikasi menunjukkan sukses, kita wajib menghapus throttle agar konfigurasi bandwidth broker kembali ke mode tidak terbatas:

# Verifikasi status migrasi dan hapus throttle secara otomatis setelah sukses
kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file reassignment.json \
  --verify

Ringkasan #

  • Replication Factor: Menentukan jumlah total salinan partisi topik di seluruh kluster broker Kafka untuk mengantisipasi kegagalan infrastruktur fisik.
  • Toleransi Matematis: Dengan RF = $R$ dan Min ISR = $M$, toleransi kegagalan tulis kita adalah $R - M$ broker crash.
  • Standar Produksi: Gunakan replication.factor=3 dikombinasikan dengan min.insync.replicas=2 sebagai konfigurasi standar untuk data transaksional yang berharga.
  • Rack Awareness: Fitur krusial untuk menyebarkan replika partisi secara merata di Availability Zone yang berbeda menggunakan parameter broker.rack.
  • Under-Replicated Partitions: Pantau terus metrik JMX UnderReplicatedPartitions untuk mendeteksi kegagalan replikasi di kluster kita.
  • Follower Fetching: Solusi modern untuk memangkas biaya lalu lintas jaringan lintas AZ dengan mengizinkan konsumen membaca dari replika follower terdekat di zona yang sama.

← Sebelumnya: Data Loss   Berikutnya: Time-Based →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact