# Arsitektur Event-Driven Skala Besar dengan Apache Kafka dan Go

> Diterbitkan oleh Literally Web ID pada 21 Oct 2026
> Sumber: https://literally.web.id/articles/arsitektur-event-driven-skala-besar-dengan-apache-kafka-dan-go

---

## 1. Intisari Kilat: Fondasi dalam Sekali Lirik

Ingat waktu insiden Black Friday tiga tahun lalu ketika database kita jebol karena lonjakan trafik checkout yang menghantam langsung dari Nginx ke PHP-FPM dan MySQL? Sejak malam itu, saya bersumpah tidak akan membiarkan arsitektur web modern tanpa penyangga asynchronous yang tangguh. Di sinilah Apache Kafka dan Go masuk sebagai penyelamat. Kita tidak sedang membicarakan antrean pesan biasa seperti Redis Queue yang gampang amnesia kalau RAM habis, melainkan sebuah *event log* terdistribusi yang mencatat setiap kejadian secara permanen.

Bayangkan Kafka sebagai buku besar raksasa di pabrik logistik, sementara aplikasi Go kita adalah para kurir cepat yang mencatat dan mengambil paket-paket tersebut secara paralel. Kuncinya ada pada tiga pilar: **Partisioning Strategi** untuk memecah beban, **Consumer Group Balancing** agar pembagian kerja adil tanpa rebutan, dan **Dead Letter Queue (DLQ) Management** untuk menampung pesan rusak tanpa bikin sistem *crash*. Begitu kita mendesain ketiganya dengan benar, sistem web kita bisa menelan jutaan *request* dari Cloudflare, menyimpannya sementara di S3/MinIO jika perlu, lalu memprosesnya di background tanpa membuat frontend ngadat.

Mari kita bedah peta perjalanannya agar Anda tidak perlu mengulang kesalahan mahal yang sama di lantai produksi.

## 2. Kompas Keputusan: Kapan Memilih Solusi Ini vs Alternatif Lain

Dalam membangun infrastruktur, salah memilih senjata berarti siap-siap begadang memperbaiki *memory leak* di tengah malam. Mari kita letakkan Kafka, RabbitMQ, dan Redis Pub/Sub di atas meja operasi.

> [!IMPORTANT]
> Jangan pernah menggunakan Kafka jika beban aplikasi Anda masih di bawah 10.000 pesan per detik dan hanya butuh *simple task queue*. Itu namanya membunuh nyamuk pakai meriam.

*   **Jika arsitektur Anda butuh *event streaming* permanen, *replayability* data, dan skala jutaan pesan per detik dari berbagai microservices Go:** Pilih **Apache Kafka**. Ia unggul dalam ketahanan data (menulis ke disk secara sekuensial) dan integrasi ekosistem yang luas.
*   **Jika Anda butuh *complex routing*, *priority queue*, dan *AMQP protocol* untuk tugas-tugas latar belakang yang relatif kecil:** Pilih **RabbitMQ**. Lebih ringan untuk di-deploy di VPS standar tanpa kluster ZooKeeper/KRaft yang rumit.
*   **Jika Anda hanya butuh *real-time broadcast* kilat tanpa peduli data hilang saat server *reboot* (misalnya notifikasi WebSocket sederhana):** Cukup gunakan **Redis Pub/Sub** atau **Redis Streams**.

> [!TIP]
> Untuk urusan performa consumer di Go, gunakan pustaka `segmentio/kafka-go` jika Anda ingin kontrol koneksi TCP yang bersih dan *idiomatic*, atau `confluent-kafka-go` (librdkafka) jika Anda memprioritaskan performa mentah C-binding di lingkungan Linux skala masif.

## 3. Contekan Konfigurasi & Parameter Paling Sering Dicari

Sebagai arsitek, saya benci dokumentasi yang bertele-tele. Berikut adalah rangkuman parameter kritikal pada file konfigurasi Kafka (`server.properties`) dan snippet koneksi Go yang wajib Anda hafal di luar kepala.

```properties
# server.properties - Tuning untuk High-Throughput di Production Linux
num.network.threads=8
num.io.threads=16
socket.send.buffer.bytes=1048576
socket.receive.buffer.bytes=1048576
socket.request.max.bytes=104857600

# Strategi Log Retention & Cleanup
log.retention.hours=72
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000

# Replikasi untuk High Availability
default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false
```

Sekarang, mari kita lihat bagaimana Go menangani partisi dan pengiriman pesan secara aman tanpa *blocking*.

```go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/segmentio/kafka-go"
)

func ProduceEvent(broker, topic string, key, value []byte) error {
	// Konfigurasi Producer dengan jaminan durabilitas tinggi
	writer := &kafka.Writer{
		Addr:                   kafka.TCP(broker),
		Topic:                  topic,
		Balancer:               &kafka.Hash{}, // Memastikan key yang sama masuk ke partisi yang sama
		BatchTimeout:           10 * time.Millisecond,
		RequiredAcks:           kafka.RequireAll, // acks=all: Mencegah kehilangan data saat broker mati
		Async:                  false,
	}
	defer writer.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	err := writer.WriteMessages(ctx,
		kafka.Message{
			Key:   key,
			Value: value,
		},
	)
	if err != nil {
		return fmt.Errorf("gagal mengirim event ke kafka: %w", err)
	}

	return nil
}
```

## 4. Koleksi Mantra One-Liner Siap Salin untuk Keseharian

Saat insiden terjadi di server produksi, Anda tidak punya waktu membaca manual. Ketik mantra-mantra CLI ini di terminal untuk menyelamatkan hari:

```bash
# 1. Cek daftar topik dan status partisi secara cepat di cluster
kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic nama-topic-anda

# 2. Membaca pesan dari awal topik (mengabaikan offset lama) untuk keperluan debugging
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic nama-topic-anda --from-beginning

# 3. Memantau lag Consumer Group secara real-time (Sangat penting saat load testing)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group nama-consumer-group

# 4. Melakukan reset offset consumer group kembali ke 0 jika terjadi kekacauan logika aplikasi
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group nama-consumer-group --topic nama-topic-anda --reset-offsets --to-earliest --execute
```

## 5. Jalur Bahaya: Dosa Besar yang Wajib Dihindari di Produksi

> [!WARNING]
> Melakukan *hardcoding* jumlah partisi tanpa rencana ekspansi masa depan adalah jalan pintas menuju kehancuran arsitektur. Partisi hanya bisa ditambah, tidak bisa dikurangi!

Berikut adalah tiga dosa besar yang sering saya temui saat *code review* junior engineer:

1.  **Mengabaikan `Key` saat Publish Pesan:** Mengirim pesan tanpa *key* (`nil`) akan membuat Kafka mendistribusikannya secara *round-robin*. Akibatnya? Urutan kejadian (*ordering*) hancur berkeping-keping. Jika user melakukan *Update Profile* lalu *Delete Profile*, pesan delete bisa sampai lebih dulu daripada update.
2.  **Processing di dalam Loop Consumer tanpa Worker Pool:** Membaca pesan dari Kafka lalu langsung melakukan *blocking query* ke database MySQL satu per satu di dalam *main goroutine* akan membuat *heartbeat timeout*. Consumer akan dianggap mati oleh Kafka, memicu *rebalance storm* yang melumpuhkan kluster.
3.  **Tidak Mengaktifkan Dead Letter Queue (DLQ):** Begitu ada payload JSON korup atau *malformed data*, consumer akan *panic* atau *retry* selamanya (infinite loop). Tanpa DLQ yang membuang pesan bermasalah ke penampungan terpisah, seluruh *pipeline* data Anda akan *stuck* total.