87. Studi Kasus: Debugging Masalah Streaming
Streaming data secara real-time semakin menjadi kebutuhan fundamental, baik untuk layanan video, audio, maupun data sensor IoT. Namun, siapa pun yang pernah membangun pipeline streaming pasti pernah menghadapi masalah aneh: lag, data hilang, duplikasi, hingga crash yang tidak jelas sumbernya. Pada artikel ini, saya akan membagikan studi kasus nyata dalam menangani masalah pada sistem data streaming berbasis Kafka, mulai dari identifikasi, replikasi bug, sampai akhirnya menemukan akar masalah dan memperbaikinya.
Latar Belakang
Sistem streaming yang kami bangun bertujuan mentransfer data dari service A (producer) ke service B (consumer) melalui Apache Kafka. Data ini sangat penting: setiap kehilangan satu event dapat menyebabkan data user tidak konsisten di service downstream. Berikut diagram arsitektur sederhananya:
flowchart LR
A[Service A
Kafka Producer] -- PUSH --> K[Kafka Topic]
K -- SUBSCRIBE --> B[Service B
Kafka Consumer]
Permasalahan yang Muncul
Secara berkala, tim menemukan bahwa consumer di Service B terkadang menerima data yang duplikat, atau bahkan tidak menerima data sama sekali. Awalnya, kami menyangka masalah ada di service B — lag network, konsumsi lambat, dsb. Tapi, ternyata problem lebih kompleks.
Gejala yang Muncul:
- Lag di metrics consumer melonjak tanpa sebab.
- Terjadi jump pada offset (offset lompat dari n ke n+10).
- Kadang, producer terlihat berhasil publish tanpa error.
Langkah 1: Mengidentifikasi Masalah
Langkah pertama: observasi dan logging. Kami menambah extensive logging pada kedua sisi:
- Producer: Logging tiap message berhasil/failed beserta offset.
- Kafka: Memantau log partisi, disk usage, dan metrics internal seperti
under-replicated partitions. - Consumer: Logging setiap offset commit, incoming message, dan status koneksi.
Kami juga menulis script sederhana untuk mensimulasikan consumer:
from kafka import KafkaConsumer
import json
consumer = KafkaConsumer(
'my-topic',
bootstrap_servers=['kafka:9092'],
group_id='debug-group',
auto_offset_reset='earliest',
enable_auto_commit=True
)
for msg in consumer:
print(f'Offset: {msg.offset}, Key: {msg.key}, Value: {msg.value}')
Langkah 2: Menganalisis Metrics
Kami menemukan anomali sebagai berikut:
| Timestamp | Producer Offset | Kafka Offset | Consumer Offset | Lag |
|---|---|---|---|---|
| 2024-06-01 10:00 | 100 | 100 | 95 | 5 |
| 2024-06-01 10:01 | 110 | 110 | 95 | 15 |
| 2024-06-01 10:02 | 120 | 100 | 95 | 5 |
Insight:
Pada 10:01 terjadi kenaikan offset producer, tetapi offset di Kafka sempat tidak naik; artinya, ada message yang tidak masuk ke Kafka. Setelah beberapa menit, offset Kafka “kembali normal”.
Langkah 3: Menyederhanakan Permasalahan
Kami menulis script untuk mensimulasikan burst saat mengirim pesan berikut:
from kafka import KafkaProducer
import json
import time
producer = KafkaProducer(
bootstrap_servers=['kafka:9092'],
value_serializer=lambda v: json.dumps(v).encode('utf-8')
)
for i in range(120):
data = {'event': f'event-{i}', 'timestamp': time.time()}
producer.send('my-topic', value=data, key=str(i).encode())
time.sleep(0.01 if i < 100 else 0.0001) # Simulate burst
producer.flush()
Hasilnya: pada burst yang tinggi, message drop tanpa error, sehingga aplikasi mengira message berhasil dikirim.
Langkah 4: Investigasi Kafka dan Jaringan
Feature Kafka yang sangat powerful, seperti acks=1, membuat delivery message jadi “fire-and-forget”, namun insecure. Setting kami ternyata mengandalkan ack default, yaitu acks=1. Untuk aplikasi critical, sebaiknya gunakan acks=all untuk memastikan message benar-benar diterima oleh semua replica broker.
Menemukan Bottleneck:
- Ditemukan saturation pada disk broker.
- Jaringan sempat terputus di reroute tertentu.
- Kafka menandai beberapa partition sebagai “under-replicated”, menyebabkan sebagian event tidak terdurable.
Diagram alir proses penulisan message Kafka:
sequenceDiagram
participant P as Producer
participant B as Broker
participant R as Replica
P->>B: Send message (acks=1)
alt acks=1
B->>P: Respond OK after leader write
else acks=all
B->>R: Replicate message
R->>B: Ack
B->>P: Respond OK after all acks
end
Dengan acks=1, message sebenarnya bisa saja belum durable di semua broker; jika leader gagal, data hilang. Sangat berbahaya untuk sistem yang butuh durability tinggi.
Langkah 5: Root Cause dan Fix
Kami melakukan beberapa eksperimen:
Mengganti acks jadi all di producer:
producer = KafkaProducer( bootstrap_servers=['kafka:9092'], value_serializer=lambda v: json.dumps(v).encode('utf-8'), acks='all' )Monitoring Partition Replica Lags secara aktif.
Ensuring Disk Health: Kapasitas disk dan IOPS harus dijaga agar broker tidak stuck.
Active Retry: Tambahkan retry logic pada error non-transient.
Setelah perubahan di atas, message loss nyaris hilang, lag menurun drastis, dan burst message tidak lagi menyebabkan silent failure.
Insight Lanjutan: Error Handling di Kode
Strategi lain: mitigasi di level aplikasi. Misal, jika send gagal atau timeout:
from kafka.errors import KafkaTimeoutError
try:
producer.send('my-topic', value=data)
except KafkaTimeoutError as e:
# Implement retry logic atau fallback
print('Timeout, retrying...')
Dan pada sisi consumer, implementasi manual offset commit agar lebih reliable:
consumer = KafkaConsumer(
'my-topic',
bootstrap_servers=['kafka:9092'],
group_id='debug-group',
enable_auto_commit=False
)
for msg in consumer:
process(msg)
consumer.commit()
Kesimpulan
Masalah pada streaming sering kali adalah kombinasi antara arsitektur distributed, network flakiness, dan asumsi yang salah pada durability. Berbekal observasi menyeluruh, logging yang baik, dan benchmark dengan skenario edge-case, kita dapat menemukan akar masalah di titik “sepele” seperti setting ack atau disk IOPS.
Takeaways untuk engineer lain:
- Always review Kafka producer config, terutama
acksdanretries. - Monitoring partisi, disk, dan replica health adalah keharusan.
- Simulasikan traffic burst dan failure mode sedini mungkin.
- Dokumentasikan investigasi agar tim lain tidak terjebak di masalah yang sama!
Selalu ingat: Streaming bukan sekadar “data lewat”, tapi soal guarantee konsistensi dan integrity user kita. Debug properly, debug deeply.
Happy debugging!
Tinggalkan komentar jika pernah mengalami masalah serupa. Saya ingin tahu solusi kalian!