tutorial

  1. Studi Kasus: Debugging Masalah Streaming

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:

TimestampProducer OffsetKafka OffsetConsumer OffsetLag
2024-06-01 10:00100100955
2024-06-01 10:011101109515
2024-06-01 10:02120100955

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:

  1. Mengganti acks jadi all di producer:

    producer = KafkaProducer(
        bootstrap_servers=['kafka:9092'],
        value_serializer=lambda v: json.dumps(v).encode('utf-8'),
        acks='all'
    )
    
  2. Monitoring Partition Replica Lags secara aktif.

  3. Ensuring Disk Health: Kapasitas disk dan IOPS harus dijaga agar broker tidak stuck.

  4. 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 acks dan retries.
  • 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!

comments powered by Disqus