Kafka memperlakukan nilai pesan sebagai rangkaian byte tanpa menafsirkan isinya, sehingga bentuk payload menjadi keputusan desain yang sepenuhnya berada di tangan aplikasi. Topik ini menjelaskan cara menyusun payload yang mandiri, standar metadata yang menyatukan informasi umum pada setiap pesan, pengelolaan ukuran payload terhadap batas broker, pemilihan key yang mendistribusikan beban secara merata, dan pemeriksaan bentuk pesan sebelum pengiriman. Setelah membaca topik ini, bentuk pesan dapat ditetapkan sebagai standar yang diperiksa mesin, bukan sekadar kesepakatan lisan.
Bentuk payload pesan#
Payload berisi data teknis yang dikirim producer dan dibaca consumer, dan formatnya dipilih dari yang paling mudah diperiksa di lingkungan kerja masing-masing. JSON menjadi pilihan umum karena formatnya dapat dibaca manusia dan tersedia pustakanya di hampir semua bahasa pemrograman. Format biner seperti Avro dipilih untuk kebutuhan throughput tinggi karena ukurannya lebih kecil dan tipenya lebih ketat. Apa pun pilihannya, format yang sama digunakan oleh seluruh producer dan consumer pada satu topic agar pembacaan tetap konsisten.
Payload disusun mandiri, artinya satu pesan memuat seluruh data yang dibutuhkan untuk memprosesnya tanpa bergantung pada pesan lain. Aturan ini penting karena pesan pada log dapat dibaca berulang kali, diambil ulang dari awal, dan diproses oleh consumer baru yang tidak pernah melihat pesan sebelumnya. Payload yang hanya berisi koreksi atas pesan sebelumnya memaksa pembaca menelusuri sejarah lengkap untuk memahami satu kejadian. Pesan yang mandiri memindahkan beban penelusuran itu ke log yang terus tersimpan.
Konsistensi tipe menjadi perhatian yang sama pentingnya dengan pemilihan format. Field bernilai waktu menggunakan satu format yang sama di seluruh aliran, field numerik tidak berubah menjadi string, dan field opsional dinyatakan secara eksplisit. Kebiasaan kecil ini mencegah consumer membuat penanganan khusus untuk setiap variasi yang muncul. Aturan yang lebih ketat lagi ditegakkan melalui skema yang diperiksa mesin sebelum pesan dikirim.
Envelope dengan metadata standar#
Envelope adalah bungkus standar yang memisahkan metadata umum dari data teknis pada setiap pesan. Envelope menyimpan empat kelompok informasi, yaitu identitas peristiwa, jenis peristiwa, waktu kejadian, dan isi teknisnya. Metadata umum itu digunakan oleh consumer untuk menyaring pesan berdasarkan jenisnya, mendeteksi pesan yang terkirim dua kali, dan menelusuri kapan sebuah kejadian benar-benar terjadi. Dengan envelope, setiap topic mengikuti satu bentuk yang sama meskipun isinya beragam.
Contoh berikut menunjukkan envelope untuk peristiwa pengeditan catatan pada aplikasi pengolah teks.
{
"event_id": "9f1c2b3a-4d5e-4f7a-8b9c-0d1e2f3a4b5c",
"event_type": "catatan.diedit",
"occurred_at": "2026-11-07T08:30:00Z",
"data": {
"id": "catatan-42",
"judul": "Daftar belanja",
"isi": "susu, roti, telur"
}
}Setiap field memegang peran yang jelas. Field event_id berupa pengenal unik sehingga consumer dapat mengabaikan pesan yang tiba dua kali saat pengiriman diulang. Field event_type mengikuti pola objek.aksi dengan huruf kecil, misalnya catatan.diedit, sehingga pemfilteran berdasarkan jenis peristiwa tidak memerlukan penguraian isi data. Field occurred_at menggunakan format ISO 8601 dalam waktu UTC dan menyatakan waktu kejadian pada sumbernya, bukan waktu pengiriman. Field data menampung isi teknisnya, sehingga field baru dapat ditambahkan tanpa mengubah bentuk envelope.
Ukuran payload#
Kafka tidak menafsirkan isi payload, tetapi broker tetap memberlakukan batas ukuran pada pesan yang masuk. Pada konfigurasi default, satu topic menolak batch pesan yang lebih besar dari 1048588 byte, yaitu sekitar 1 MiB, lewat konfigurasi max.message.bytes. Producer menetapkan batas yang setara pada sisi pengirimannya lewat max.request.size dengan nilai default 1048576 byte. Pesan yang melebihi batas tidak pernah masuk ke log, karena producer menolaknya dengan error RecordTooLargeException sebelum atau saat pengiriman. Batas ukuran mengikat sebelum pemeriksaan bentuk apa pun, sehingga payload yang terlalu besar gagal meskipun strukturnya benar.
Envelope menambah beban ukuran yang berulang pada setiap pesan. Field metadata beserta nama fieldnya disertakan kembali pada setiap pengiriman, sedangkan bagian data memuat isi yang benar-benar dikirim. Pada pesan yang kecil, metadata dapat melampaui isi datanya, sehingga ukuran payload diukur dan bukan ditebak. Skrip berikut mengukur pecahan metadata pada contoh envelope pesan.json dan dijalankan dari folder topik dengan perintah python3 -B ukuran-payload.py.
import json
with open("pesan.json", encoding="utf-8") as f:
envelope = json.load(f)
utuh = json.dumps(envelope, ensure_ascii=False).encode("utf-8")
data = json.dumps(envelope["data"], ensure_ascii=False).encode("utf-8")
metadata = len(utuh) - len(data)
print(f"envelope utuh : {len(utuh):4d} byte")
print(f"data saja : {len(data):4d} byte")
print(f"metadata : {metadata:4d} byte ({metadata * 100 // len(utuh)} persen)")envelope utuh : 208 byte
data saja : 75 byte
metadata : 133 byte (63 persen)Pada contoh di atas, metadata menyerap 63 persen dari total ukuran karena isi pesannya kecil. Rasio itu menurun seiring bertambahnya isi data, tetapi overhead metadata tetap dibayar pada setiap pesan. Pengukuran menggunakan byte hasil encoding UTF-8, dan byte hasil serialisasi itulah yang dihitung oleh broker terhadap batas ukurannya.
Dua langkah biasa digunakan untuk mengelola ukuran payload. Pertama, kompresi diaktifkan lewat konfigurasi compression.type pada topic, dengan pilihan codec gzip, snappy, lz4, dan zstd, sedangkan nilai default producer mempertahankan codec yang dipilih producer. Kedua, objek besar seperti gambar atau arsip tidak disematkan ke dalam pesan, melainkan disimpan di tempat yang sesuai dan pesan hanya membawa referensinya. Menaikkan max.message.bytes tetap dimungkinkan, tetapi batch terbesar yang dipindahkan ke consumer juga ikut membesar, sehingga keputusan itu diperhitungkan dengan throughput pembacaannya.
Memilih key yang merata#
Key menentukan partisi tempat pesan berlabuh dan dengan itu menentukan jaminan urutan per key. Pemilihan key juga menentukan keseimbangan beban, karena jumlah nilai yang berbeda (cardinality) beserta sebarannya menentukan penyebaran pesan ke partisi. Key dengan kardinalitas tinggi dan sebaran yang merata, misalnya pengenal entitas, menyebar ke semua partisi secara seimbang. Key dengan kardinalitas rendah, misalnya jenis peristiwa yang hanya ada beberapa nilai, menumpahkan beban ke sebagian kecil partisi sementara partisi lain sepi. Key yang menimbulkan ketimpangan semacam ini dikenal sebagai hot key, dan pemilihannya dihindari pada topic yang membutuhkan distribusi merata.
Tabel berikut menjadi panduan pemilihan key menurut sifat aliran datanya.
| Bentuk key | Kardinalitas | Distribusi | Cocok untuk |
|---|---|---|---|
Pengenal entitas, misalnya catatan-42 | Tinggi | Merata ke semua partisi | Urutan dan keadaan per entitas |
| Gabungan entitas dan waktu | Tinggi | Merata ke semua partisi | Aliran besar dengan sejarah panjang per entitas |
| Nilai kategori, misalnya jenis peristiwa | Rendah | Menumpuk di beberapa partisi | Tidak cocok sebagai key utama |
| Tanpa key | Tidak ada | Merata secara berputar | Aliran yang tidak membutuhkan urutan per key |
Bila key kardinalitas rendah tidak terhindarkan, gabungkan nilainya dengan pengenal entitas sehingga kombinasi yang dihasilkan tetap merata. Aliran yang mengirim pesan tanpa key memperoleh distribusi yang merata, tetapi kehilangan jaminan urutan karena pesan tidak dikelompokkan menurut apa pun. Keputusan ini harus disesuaikan dengan pertanyaan yang akan dijawab oleh aplikasi pembacanya.
Memvalidasi envelope sebelum dikirim#
Validasi envelope pada sisi producer menahan pesan rusak sebelum pesan masuk ke broker. Pemeriksaan meliputi keberadaan event_id, pola event_type, format occurred_at, dan bentuk data. Skrip berikut memeriksa empat aturan tersebut, lalu menerapkannya pada contoh envelope dan pada pesan rusak yang sengaja dibuat. Skrip membaca berkas pesan.json yang berada di sampingnya, sehingga dijalankan dari folder topik dengan perintah python3 -B validasi-envelope.py.
import json
import re
from datetime import datetime
def validasi(pesan):
"""Kembalikan daftar pelanggaran aturan envelope pada pesan."""
error = []
if not isinstance(pesan.get("event_id"), str) or not pesan["event_id"]:
error.append("event_id wajib string yang tidak kosong")
if not re.fullmatch(r"[a-z0-9]+(\.[a-z0-9]+)+", str(pesan.get("event_type", ""))):
error.append("event_type wajib mengikuti pola objek.aksi")
try:
datetime.fromisoformat(str(pesan.get("occurred_at", "")).replace("Z", "+00:00"))
except ValueError:
error.append("occurred_at wajib timestamp ISO 8601")
if not isinstance(pesan.get("data"), dict):
error.append("data wajib berupa object")
return error
with open("pesan.json", encoding="utf-8") as f:
contoh = json.load(f)
rusak = {
"event_id": "",
"event_type": "Catatan Diedit",
"occurred_at": "besok pagi",
"data": [],
}
for nama, pesan in (("pesan.json", contoh), ("pesan rusak", rusak)):
error = validasi(pesan)
status = "valid" if not error else "TIDAK valid"
print(f"{nama:12s}: {status}")
for e in error:
print(f" - {e}")pesan.json : valid
pesan rusak : TIDAK valid
- event_id wajib string yang tidak kosong
- event_type wajib mengikuti pola objek.aksi
- occurred_at wajib timestamp ISO 8601
- data wajib berupa objectPesan contoh lolos seluruh aturan, sedangkan pesan rusak ditolak dengan alasan yang menyebut setiap pelanggarannya. Pesan rusak pada skrip memuat empat pelanggaran sekaligus dan semuanya dilaporkan dalam satu kali pemeriksaan, sehingga perbaikannya tidak perlu dilakukan berulang-ulang. Daftar aturan berkembang mengikuti kebutuhan topic, misalnya batas panjang string atau tipe field tertentu pada data. Prinsipnya tetap sama, yaitu pemeriksaan yang dilakukan mesin lebih dapat diandalkan daripada kesepakatan yang hanya berupa kebiasaan.
Ringkasan#
- Payload disusun mandiri sehingga setiap pesan memuat seluruh data yang dibutuhkan untuk diproses tanpa bergantung pada pesan lain.
- Envelope menyatukan metadata umum berupa
event_id,event_type,occurred_at, dandatapada setiap pesan, dengan ukuran totalnya dijaga di bawah batasmax.message.bytestopic. - Key dipilih dengan kardinalitas tinggi yang sebarannya merata, sedangkan key kardinalitas rendah menumpahkan beban ke sebagian kecil partisi.
- Validasi envelope pada producer menahan pesan rusak sebelum pesan masuk ke broker.
Referensi#
- Apache Kafka documentation: Getting started — Apache Software Foundation — pengantar model pesan Kafka yang memuat key dan nilai pada setiap catatan log.
- RFC 3339: Date and Time on the Internet — IETF
— spesifikasi format penanda waktu yang menjadi dasar penulisan
occurred_atberformat ISO 8601.