Masalah dan Cakupan
Desain sebuah sistem centralized logging yang digunakan bersama oleh beberapa tim rekayasa perangkat lunak (engineering teams). Seratus ribu service instance, container, dan batch job menghasilkan 1 juta event per detik pada kondisi stabil (steady state), dengan rata-rata 600 byte data mentah per event. Sebuah insiden besar dapat mempertahankan 3 juta event per detik selama 15 menit karena request yang gagal, retry, dan stack trace semuanya meningkat secara bersamaan. Target p99 dari pembuatan event hingga visibilitas pencarian adalah 30 detik. Kueri umum dalam 15 menit terakhir, dengan filter tenant, waktu, service, environment, dan tingkat keparahan (severity), harus selesai di bawah 2 detik pada p95.
Pengguna membutuhkan filter berdasarkan waktu, service, host, severity, dan traceId, ditambah pencarian teks lengkap (full-text search) berbatas, unduhan, dan peringatan (alert). Kelas-kelas log memiliki persyaratan retensi dan keandalan yang berbeda. Debug log dapat memiliki masa retensi yang pendek dan boleh di-sample selama keadaan darurat. Operational error membutuhkan retensi yang tahan lama (durable). Log audit keamanan tidak boleh menggunakan kebijakan degradasi biasa. Sistem ini juga memerlukan kuota tenant, redaksi field (field redaction), audit akses, manajemen siklus hidup (lifecycle management), dan pemulihan data historis (historical restoration).
Target skala, latensi, retensi, dan keandalan ini merupakan input wawancara, bukan komitmen publik dari vendor logging tertentu. Cakupannya tidak mencakup implementasi mesin pencari secara utuh atau menulis ulang message broker selama wawancara. Cakupan ini juga tidak mengharuskan peniruan arsitektur internal suatu perusahaan. Soal system design publik tahun 2026 masih meminta kandidat untuk mendesain centralized logging dengan penanganan lonjakan (burst handling), pencarian, retensi, dan isolasi tenant. Data model log OpenTelemetry yang stabil, panduan pemecahan masalah Collector-nya, serta dokumentasi Elastic mengenai data tier dan mapping explosion memberikan bukti primer untuk batasan-batasan rekayasa yang penting ini.
Apa yang Dinilai oleh Pewawancara
Pertama, dapatkah kandidat memisahkan penerimaan data yang tahan lama (durable acceptance) dari visibilitas pencarian langsung? Gateway dapat mengirim konfirmasi penerimaan (acknowledgment) suatu event setelah melakukan commit ke durable stream yang direplikasi. Search index mungkin mengalami jeda (lag) hingga puluhan detik. Jika status berhasil mengharuskan penulisan ke cluster pencarian, pemeliharaan dan penskalaan indeks akan langsung memberikan backpressure ke setiap producer.
Kedua, apakah kandidat mengenali kegagalan yang saling berkorelasi (correlated failure) selama insiden? Waktu saat log paling bernilai justru merupakan saat di mana error aplikasi, lonjakan retry (retry storm), dan tekanan pada search cluster sering kali meningkat bersamaan. Jawaban yang lengkap mencakup disk buffering lokal, durable queue pusat, backpressure, kapasitas terbatas (finite capacity), pembuangan berbasis prioritas (priority-based shedding), dan jumlah data yang dibuang (drop counts) yang terukur. Hanya mengatakan "tambahkan Kafka dan Elasticsearch" tidak menyelesaikan alur penanganan kegagalan.
Ketiga, apakah rencana indexing memahami biaya dan kardinalitas? Mengindeks setiap atribut JSON sembarangan secara dinamis memungkinkan field ber-kardinalitas tinggi menciptakan mapping, kamus (dictionaries), dan overhead shard. Desain yang baik hanya mengindeks field yang stabil, sering dikueri, dan bertipe data jelas (well-typed). Atribut lain tetap dapat disimpan tanpa harus diindeks secara default.
Keempat, apakah isolasi tenant mencakup proses ingestion maupun kueri? Identitas tenant harus berasal dari kredensial terotentikasi, bukan dari tenantId yang disediakan di dalam body log. Satu tenant bervolume tinggi, regular expression yang terlalu luas, atau ledakan field tidak boleh menghabiskan antrean bersama, thread indexing, cache, atau konkurensi kueri.
Terakhir, apakah kapasitas, semantik pengiriman, keamanan, dan validasi membentuk satu sistem yang koheren? Kandidat harus menghitung throughput mentah dan backlog lonjakan, mengakui bahwa pengiriman at-least-once menghasilkan duplikat, menjelaskan mengapa log audit dan log debug memerlukan kebijakan yang berbeda, serta menggunakan canary end-to-end untuk membuktikan bahwa kehilangan data tidak pernah terjadi secara tersembunyi (silent loss).
Pertanyaan Klarifikasi Sebelum Menjawab
- Log mana yang tidak boleh hilang? Event audit dan keamanan memerlukan retensi durable. Debug log boleh di-sample atau dibuang berdasarkan kebijakan degradasi eksplisit.
- Di mana batas keberhasilan penerimaan data? Gateway pusat memberikan acknowledgment setelah melakukan commit event ke durable stream yang direplikasi di seluruh availability zone, tanpa menunggu refresh pada search index.
- Bolehkah logging memblokir producer? Log aplikasi biasa tidak boleh memblokir request bisnis secara sinkron. Node agent menggunakan batching asinkron dan disk lokal berkapasitas terbatas.
- Apa pola kueri utamanya? Filter terstruktur dengan rentang waktu dan tenant, pencarian persis
traceId, dan pencarian teks lengkap dalam rentang waktu terbatas. - Apakah pengurutan global (global ordering) diperlukan? Tidak. Pertahankan urutan perkiraan di dalam satu instance sumber dan gunakan timestamp event serta timestamp observasi untuk membantu mengurutkan event lintas sumber.
- Apa asumsi retensinya? Debug log disimpan 24 jam di hot index dan 7 hari di arsip mentah. Operational log disimpan 7 hari di hot tier dan 90 hari di arsip. Log audit disimpan 30 hari agar dapat dicari dan 365 hari di arsip immutable.
- Apakah kita memerlukan active write lintas region? Desain utama mengumpulkan data ke dalam pipeline regional. Control plane terpadu dan kueri disaster-recovery dapat membaca dari arsip.
- Apakah kita mengindeks setiap field? Tidak. Field tingkat atas yang stabil dan atribut yang masuk daftar izin (allowlist) boleh diindeks. Atribut sembarangan ber-kardinalitas tinggi hanya disimpan secara default.
- Bagaimana nilai sensitif ditangani? SDK dan node agent mencegah atau menyensornya (redact) terlebih dahulu, dan pemroses pusat (central processor) memeriksa kembali. Rahasia (secrets) dan token tidak boleh masuk ke dalam log.
- Seberapa luas sebuah kueri diizinkan? Wajibkan rentang waktu, cursor pagination, batas kuota scan (scan budget), batas konkurensi, dan pembatalan (cancellation). Ekspor historis berukuran besar menggunakan background job asinkron.
Kerangka Jawaban 30 Detik
"Aplikasi menulis ke stdout atau SDK asinkron. Node agent melakukan batching, redaksi, dan menggunakan disk spool berkapasitas terbatas. Gateway regional mengotentikasi beban kerja (workload), mengikat tenant, menerapkan kuota, dan memvalidasi format sebelum menulis ke durable stream yang direplikasi di seluruh availability zone. Commit tersebut adalah batas konfirmasi penerimaan (acknowledgment boundary). Processor menormalkan event, menulis record mentah ke object storage, dan menulis field yang disetujui beserta teks terpilih ke hot search index. Layanan kueri mewajibkan predikat tenant dan waktu, serta merutekan rentang pencarian ke storage tier hot, warm, dan arsip. Traffic mentah stabil sekitar 600 MB/s atau 51,84 TB/hari. Lonjakan 3x selama 15 menit menciptakan backlog sekitar 1,08 TB di atas pemrosesan normal. Pengiriman bersifat at-least-once dengan deduplikasi eventId. Selama beban berlebih (overload), pertahankan log audit dan error terlebih dahulu, lakukan sampling pada debug log terlebih dahulu, dan tampilkan setiap data yang dibuang sebagai metrik yang dapat memicu alert."
Pembahasan Mendalam Langkah demi Langkah
Mulailah dengan enam invarian:
- Request bisnis biasa tidak boleh bergantung secara sinkron pada platform remote logging.
- Sistem pusat mengonfirmasi penerimaan event hanya setelah data mencapai durable buffering yang direplikasi.
- Identitas tenant berasal dari otentikasi; ingestion, penyimpanan, pencarian, dan ekspor tidak boleh melewati batas tenant.
- Log audit tidak menggunakan kebijakan sampling dan penolakan data (shedding) yang diterapkan pada debug log.
- Atribut pengguna sembarangan tidak diindeks secara dinamis secara default, sehingga field ber-kardinalitas tinggi tidak dapat memperbesar skema tanpa batas.
- Pembuangan data (drops), keterlambatan (delays), kegagalan parsing, dan kegagalan redaksi dapat diukur dan tidak pernah terjadi secara tersembunyi.
Langkah 1: Tentukan jalur pengumpulan dan batas konfirmasi penerimaan (acknowledgment boundary).
Application stdout / asynchronous SDK
-> node agent or sidecar: batch, compress, redact, local disk spool
-> regional ingestion gateway: authenticate, bind tenant, quota, mandatory redaction, format and size limits
-> durable stream replicated across availability zones
-> normalization and routing processors
-> raw object-storage archive
-> hot search index
-> alerts and streaming subscriptions
-> query coordinator -> hot / warm / archive readersAplikasi biasanya menulis ke stdout sehingga node agent tetap terpisah (decoupled) dari proses bisnis. SDK asinkron cukup beralasan untuk event yang terstruktur secara eksplisit, tetapi ia tetap menulis ke antrean in-memory atau agent lokal. Agent melakukan batching berdasarkan ukuran byte dan waktu, membatasi ukuran event individual, menyimpan posisinya secara persisten, dan menggunakan disk spool berkapasitas terbatas selama kegagalan jaringan. Saat disk penuh, ia mengikuti kebijakan berdasarkan kelas log alih-alih memblokir proses selamanya atau menghabiskan kapasitas disk tanpa batas.
Gateway regional memperoleh tenant, service, dan environment dari identitas mTLS, identitas workload, atau kredensial berumur pendek, menimpa field palsu yang ada di dalam body. Gateway menerapkan rate limit, mendekode kompresi, melakukan pemeriksaan skema dasar, memberlakukan ukuran maksimum event, dan menerapkan redaksi rahasia serta token wajib sebelum data masuk ke central durable buffer. Gateway memberikan konfirmasi penerimaan hanya setelah event direplikasi ke dalam durable stream di seluruh availability zone. Pencarian, arsip, dan alert adalah konsumen yang terpisah, sehingga satu konsumen yang gagal tidak menjadi dependensi langsung dari setiap producer.
Langkah 2: Gunakan data model umum dengan titik ekstensi yang terkontrol.
LogEvent(
eventId, timestamp, observedTimestamp,
tenantId, service, environment, instance,
severityNumber, severityText, body,
traceId, spanId, schemaVersion,
attributes, sensitivityClass
)timestamp adalah waktu saat event terjadi, sedangkan observedTimestamp adalah waktu saat sistem pengumpulan pertama kali melihatnya. Jika jam pada mesin sumber (source clock) mengalami pergeseran (drift), field yang kedua tetap menunjukkan urutan ingestion dan keterlambatan (delay). traceId dan spanId menghubungkan log dengan distributed trace. severityNumber mendukung perbandingan yang dinormalisasi sementara severityText mempertahankan susunan kata asli dari producer. schemaVersion memungkinkan processor memperbarui aturan parsing dengan aman.
Field tingkat atas yang stabil memiliki tipe data dan indeks eksplisit. attributes menyimpan data terstruktur tambahan, tetapi hanya field yang terdaftar dalam daftar izin (allowlist) yang boleh masuk ke mapping indeks. Atribut yang tidak dikenal dapat menggunakan flattened object, kolom key-value, atau raw body. Jika field yang sama berubah dari angka menjadi objek, processor akan mengarantinanya sebagai kegagalan parse atau menulisnya ke field dengan versi baru. Satu deployment yang buruk tidak boleh merusak keseluruhan indeks bersama.
Agent dapat menghasilkan eventId dari instance sumber, boot epoch, dan sequence lokal. Pengiriman bersifat at-least-once, sehingga agent akan mencoba lagi (retry) jika tidak menerima konfirmasi penerimaan. Konsumen dan operasi penulisan indeks menggunakan eventId secara idempoten. Jendela deduplikasi memiliki batas waktu, dan arsip mungkin tetap menyimpan data duplikat. Kueri dan agregasi harus memahami semantik ini daripada menjanjikan pengiriman end-to-end exactly-once yang mahal dan rentan rusak.
Langkah 3: Rencanakan pemartisian dan isolasi tenant.
Durable stream diskalakan melalui partisi virtual. Kunci perutean (routing key) dapat melakukan hashing pada (tenantId, sourceInstance), menjaga perkiraan urutan untuk satu sumber sekaligus mendistribusikan beban satu tenant ke beberapa partisi. Mempartisi hanya berdasarkan tenantId membuat tenant besar menjadi hotspot. Pemartisian acak murni akan menghilangkan keterurutan lokal dari sumber. Tenant besar dapat menerima kumpulan partisi khusus (dedicated partition pool) sementara tenant kecil berbagi kumpulan partisi, dan control plane dapat menyeimbangkan kembali alokasi tersebut tanpa mengubah format event.
Setiap tenant memiliki kuota untuk kapasitas byte ingest, laju event, burst token, backlog lokal dan pusat, jumlah field terindeks, hot storage, konkurensi kueri, byte yang di-scan, dan tugas ekspor. Penolakan dan degradasi dicatat per tenant. Selama kelebihan beban sistem, urutan prioritasnya adalah:
- Pertahankan event audit dan keamanan.
- Pertahankan error dan event operasional penting.
- Lakukan sampling pada peringatan (warning) berulang, log informasi, dan log debug sesuai kebijakan yang dinyatakan.
- Tolak kueri luas dan tugas ekspor baru yang berprioritas rendah.
Hot index bersama dapat digunakan untuk tenant kecil, tetapi setiap dokumen, cache key, dan rencana kueri wajib menyertakan tenantId yang terpercaya. Tenant besar atau yang diatur ketat oleh regulasi dapat menggunakan indeks dan batas enkripsi yang terisolasi. Desain ini sebaiknya tidak membuat banyak shard harian yang kosong untuk setiap tenant kecil, dan juga tidak menempatkan setiap tenant ke dalam satu indeks bersama tanpa batas.
Langkah 4: Pisahkan arsip mentah dari search index.
Object storage menampung event mentah yang dinormalisasi dalam file kolumnar besar terkompresi yang dipartisi berdasarkan region, tenant, tanggal, jam, dan secara opsional service. Ini adalah sumber jangka panjang berbiaya rendah untuk ekspor kepatuhan (compliance export), pemindaian historis, dan membangun ulang hot index yang rusak. Modul penulisan (writers) menggabungkan event ke dalam objek berukuran memadai alih-alih membuat satu objek per baris log.
Hot search index hanya menyimpan data terbaru yang perlu dicari. Field yang stabil menggunakan inverted index atau column-oriented index, sementara pengindeksan teks lengkap dari body log dapat bervariasi berdasarkan kelas log. Request ID ber-kardinalitas tinggi, user ID, atau tag sembarangan tetap menjadi stored field jika tidak sering dikueri. traceId juga memiliki kardinalitas tinggi, tetapi memiliki kasus penggunaan pencarian persis yang jelas, sehingga dapat menggunakan field pencarian persis khusus dengan masa retensi terbatas daripada menjadikannya preseden untuk semua dynamic field.
Lifecycle controller memindahkan data berdasarkan kelasnya dari tier hot ke warm, cold, frozen, atau arsip. Hot storage memiliki lebih banyak compute dan replika untuk penulisan dan pencarian berlatensi rendah. Data yang lebih lama berbiaya lebih murah dan mentolerir akses yang lebih lambat. Penghapusan retensi harus mencakup indeks, arsip, cache, salinan ekspor, dan legal hold. Menghapus satu search index bukanlah alur kerja penghapusan yang lengkap.
Langkah 5: Bangun jalur kueri yang terkontrol.
API kueri memperoleh tenantId dari sesi dan secara default mewajibkan startTime, endTime, serta service atau kondisi selektif lainnya. Koordinator memeriksa rentang waktu dan kelas log, lalu merutekan request ke hot index, warm storage, atau pemindaian arsip asinkron. Contoh antarmukanya adalah:
POST /logs/search
{ startTime, endTime, services, severities, traceId, query, cursor, limit }
-> { events[], nextCursor, partial, scannedBytes }
POST /logs/exports
{ startTime, endTime, filters }
-> { jobId }Hasil kueri menggunakan kunci pengurutan stabil (timestamp, eventId) dan cursor pagination alih-alih offset pagination yang dalam (deep offset). Kueri interaktif memiliki batasan pada byte yang di-scan, baris yang dikembalikan, waktu eksekusi, dan konkurensi. Saat limit tercapai, respons akan mengembalikan penanda partial eksplisit alih-alih mengabaikan data secara diam-diam. Regular expression yang luas, pencarian teks lengkap 90 hari, dan ekspor besar masuk ke antrean asinkron dan dapat dibatalkan. Metadata untuk filter umum dapat di-cache, tetapi hasil kueri tidak dapat digunakan bersama antar-tenant tanpa isolasi total.
Target p95 di bawah 2 detik berlaku untuk kueri terfilter yang selektif dalam 15 menit terakhir pada cluster yang sehat. Pemindaian teks lengkap tanpa batas pada semua data yang tersimpan tidak memiliki SLO yang sama. Mendefinisikan kelas kueri jauh lebih kredibel daripada menjanjikan bahwa setiap kueri akan berjalan cepat.
Langkah 6: Hitung kapasitas.
Throughput mentah pada kondisi stabil adalah:
1,000,000 events/s × 600 bytes = 600 MB/s
600 MB/s × 86,400 s = 51.84 TB/dayTraffic meningkat dari 1 juta menjadi 3 juta event per detik selama 15 menit. Jika pemrosesan downstream hanya mampu mempertahankan laju kondisi stabil, sistem harus menyerap akumulasi backlog tambahan ini:
(3,000,000 - 1,000,000) × 600 bytes × 900 s = 1.08 TBLonjakan tersebut menghasilkan total 1,62 TB selama 15 menit tersebut, tetapi 0,54 TB merupakan baseline yang ditangani oleh pemrosesan kondisi stabil pada saat yang sama. Buffering di dunia nyata juga memerlukan replikasi, overhead batching, kapasitas pemulihan, dan batas aman (headroom), sehingga 1,08 TB bukanlah angka final untuk pembelian perangkat keras.
Jika hanya 20% log yang masuk ke hot index terstruktur atau full-text dan bertahan di sana selama 7 hari, input mentah sebelum overhead indeks tetap sebesar:
51.84 TB/day × 20% × 7 = 72.576 TBUkuran indeks sebenarnya bergantung pada field, kompresi, shard, dan replika, serta harus diukur melalui pengujian beban (load testing). Arsip mentah selama sembilan puluh hari adalah 51.84 TB × 90 = 4.6656 PB, atau sekitar 4,67 PB sebelum kompresi. Skala sebesar ini membuat tiering penyimpanan, retensi berbasis kelas, kompresi, dan eliminasi log bernilai rendah menjadi lebih penting daripada sekadar memperbesar search cluster.
Tentukan jumlah partisi dari kapasitas byte yang berkelanjutan per partisi, event per partisi, dan kecepatan replay yang diperlukan. Pengujian kapasitas harus menggabungkan simulasi kehilangan satu availability zone, proses catch-up konsumen, dan lonjakan traffic 3x sambil memastikan usia pesan tertua (oldest-message age) pada akhirnya kembali normal. Menghitung jumlah event saja tidak cukup karena stack trace dapat mengubah ukuran rata-rata log secara drastis.
Langkah 7: Tangani backpressure, lonjakan log, dan pemadaman downstream.
Setiap lapisan memiliki kapasitas terbatas: memori SDK, disk agent, koneksi gateway, retensi stream, konkurensi processor, antrean penulisan indeks, dan thread kueri. Sistem menyebarkan tekanan melalui retry-after, batch yang lebih kecil, penghentian sementara konsumen (paused consumers), dan antrean prioritas. Saat disk agent mendekati batasnya, agent akan melakukan sampling pada debug log terlebih dahulu sesuai kebijakan dan mencatat counter lokal berdasarkan kelas data yang dibuang. Event audit menggunakan antrean cadangan terpisah atau memicu kebijakan kegagalan bisnis secara eksplisit.
Panduan pemecahan masalah OpenTelemetry Collector mencatat bahwa tujuan (destination) yang tidak tersedia atau ukuran Collector yang terlalu kecil sama-sama dapat menyebabkan data terbuang (drops). Antrean pengiriman dan mekanisme retry dapat menangani kegagalan sementara, tetapi antrean yang terlalu besar juga dapat menciptakan tekanan memori. Oleh karena itu, "mengaktifkan retry" bukanlah rencana keandalan yang lengkap. Pantau utilisasi antrean, usia event tertua, penolakan, kegagalan permanen, dan memori proses, serta picu alert sebelum kapasitas habis.
Jika index cluster tidak tersedia, durable stream akan terus menerima data, dan konsumen arsip mentah serta konsumen indeks akan berjalan secara independen. Selama pemulihan, konsumen indeks mengejar ketertinggalan dengan keadilan antar-tenant (tenant fairness) dan batasan kecepatan replay agar tidak membebani kembali cluster yang baru saja pulih. Saat proses indexing tertinggal, UI akan menampilkan watermark kesegaran pencarian (search freshness watermark) dan interval waktu yang hilang. Pengguna tidak boleh mengartikan "tidak ada hasil pencarian" sebagai "tidak ada log yang tercatat".
Langkah 8: Sempurnakan siklus keamanan, privasi, dan penghapusan data.
Kontrol data sensitif terbaik adalah menghindari pembuatan nilai tersebut sejak awal. SDK menyediakan daftar izin (allowlist) untuk structured field. Agent menyensor pola umum token, kata sandi, cookie, dan data pribadi. Gateway menerapkan aturan wajib sebelum data masuk ke central durable stream, dan processor selanjutnya melakukan redaksi semantik berbasis skema serta mengarahkan event yang bermasalah ke karantina. Raw body tidak boleh melewati pemeriksaan keamanan hanya karena data tersebut hanya dialirkan ke arsip.
Transportasi data menggunakan mTLS atau identitas beban kerja berumur pendek, dan data dienkripsi saat istirahat (at rest) dengan batas kunci enkripsi per environment atau per tenant yang teregulasi. RBAC membatasi akses berdasarkan tenant, environment, service, field, dan rentang waktu. Kueri, ekspor, perubahan retensi, dan legal hold menghasilkan event audit akses yang immutable. Field yang sangat sensitif dapat menggunakan enkripsi tingkat field (field-level encryption) atau dihapus sepenuhnya; menyembunyikannya di antarmuka UI saja tidak cukup.
Penghapusan data adalah alur kerja yang dapat dilacak di seluruh hot index, warm tier, partisi objek, cache, dan salinan ekspor. Jika retensi audit bertentangan dengan permintaan penghapusan privasi, kebijakan produk dan hukum harus menetapkan prioritas, pengecualian, dan legal hold. Sistem menjalankan kebijakan eksplisit tersebut; sistem tidak dapat berdalih dengan alasan "log bersifat immutable" untuk menghindari kewajiban penghapusan data.
Langkah 9: Buktikan keandalan sistem dengan metrik dan fault injection.
Metrik inti mencakup latensi p50/p95/p99 dari pembuatan log hingga gateway, dari gateway ke durable stream, dari stream ke arsip, dan dari stream hingga terlihat di pencarian; utilisasi antrean, usia event tertua, percobaan ulang (retries), dan data terbuang di setiap tahap; volume ingest tenant, throttling, kardinalitas field, dan biaya; penolakan indeks, pertumbuhan mapping, byte yang di-scan, timeout kueri, pembatalan, dan hit cache; kegagalan redaksi, penolakan otorisasi, dan keberhasilan pemulihan arsip.
Canary end-to-end menulis event terstruktur dengan ID unik dari setiap region setiap menit dan memverifikasi penerimaan durable, visibilitas pencarian, keberadaan di arsip objek, dan penghapusan retensi pada akhirnya. Rekonsiliasi jumlah membandingkan total data yang dikirim agent, diterima gateway, di-commit ke stream, ditulis ke arsip, dan berhasil diindeks. Duplikat yang dapat dijelaskan diperbolehkan. Perbedaan data yang tidak diketahui penyebabnya dianggap sebagai masalah.
Uji coba kegagalan (fault tests) mencakup simulasi lonjakan log 3x selama 15 menit, pemadaman pencarian selama 30 menit, throttling object storage, hilangnya satu availability zone, beban berlebih dari satu tenant, serangan field ber-kardinalitas tinggi, skema yang tidak valid, pergeseran jam sumber, injeksi data sensitif, disk agent yang habis, batch duplikat, replay stream, dan pembangunan ulang hot index dari arsip. Asersi kritisnya adalah: event audit tetap dapat dipulihkan sesuai kebijakan, setiap log biasa yang dibuang memiliki bukti terkait tenant, kelas, waktu, dan jumlah, serta pengguna dan sistem alert dapat melihat informasi penurunan kesegaran pencarian (degraded search freshness).
Contoh Jawaban Berkualitas Tinggi
"Pertama-tama, saya akan memisahkan penerimaan data yang tahan lama (durable acceptance) dari visibilitas pencarian. Aplikasi menulis ke stdout atau SDK asinkron, dan node agent menangani batching, redaksi, serta disk buffering berkapasitas terbatas, sehingga gangguan pada logging tidak memblokir request bisnis biasa secara sinkron. Gateway regional memperoleh identitas tenant dari workload identity, menegakkan kuota dan aturan format, kemudian melakukan commit batch ke durable stream yang direplikasi di seluruh availability zone. Ini adalah titik konfirmasi penerimaan pusat. Search index dan object storage archive membaca data secara asinkron.
Event memiliki field tingkat atas yang stabil untuk waktu event, waktu observasi, tenant, service, environment, instance, tingkat keparahan (severity), body, traceId, spanId, versi skema, dan tingkat sensitivitas. Atribut sembarangan hanya disimpan secara default. Hanya field yang stabil, bertipe data jelas, dan memiliki nilai kueri nyata yang dimasukkan ke dalam indeks, untuk mencegah atribut ber-kardinalitas tinggi menyebabkan ledakan mapping dan pembengkakan indeks. Pengiriman bersifat at-least-once. Agent mencoba ulang dengan eventId yang stabil, dan penulisan indeks bersifat idempoten, meskipun arsip mungkin tetap menyimpan data duplikat yang teridentifikasi.
Object storage menyimpan record mentah jangka panjang yang dapat di-replay, sedangkan hot search tier hanya menyimpan data terbaru yang perlu dicari. Kueri memerlukan identitas tenant dan rentang waktu yang terpercaya, dirutekan ke tier hot, warm, dan arsip, serta dibatasi dalam hal byte yang di-scan, konkurensi, dan ukuran hasil. Pencarian teks lengkap historis yang luas dan tugas ekspor dialihkan menjadi background job asinkron. Tenant kecil berbagi indeks dan tenant besar dapat diisolasi, tetapi kuota ingest, backlog, field, dan kueri selalu diterapkan per tenant.
Pada kondisi stabil, ingest mentah adalah 600 MB/s atau 51,84 TB/hari. Lonjakan 3x selama 15 menit menambahkan backlog sekitar 1,08 TB jika pemrosesan downstream tetap berada pada kapasitas stabil. Mengindeks hanya 20% data selama 7 hari masih menghasilkan sekitar 72,6 TB sebelum overhead indeks, sementara arsip mentah selama 90 hari membutuhkan sekitar 4,67 PB sebelum kompresi. Oleh karena itu, pengindeksan selektif, retensi berbasis kelas, dan tiering penyimpanan adalah hal yang wajib diterapkan.
Selama kegagalan, durable stream menyerap backlog jangka pendek, dan konsumen arsip serta indeks dapat pulih secara independen. Setiap buffer memiliki kapasitas terbatas. Sistem mempertahankan event audit dan error terlebih dahulu, melakukan sampling pada event debug terlebih dahulu, serta mengekspos data yang dibuang, usia pesan tertua, dan watermark kesegaran pencarian ke sistem pemantauan dan UI. Terakhir, saya akan menjalankan canary unik melalui producer, stream, indeks, dan arsip, serta menyimulasikan traffic 3x, pemadaman downstream, field ber-kardinalitas tinggi, dan kehabisan disk untuk membuktikan bahwa tidak ada data yang hilang tanpa terdeteksi dan bahwa indeks dapat dibangun kembali dari arsip."
Kesalahan Umum
- Memanggil API remote logging secara sinkron dari aplikasi → gangguan pada logging akan merusak request bisnis
→ tulis ke agent asinkron lokal dengan buffering terbatas dan degradasi eksplisit.
- Hanya memberi konfirmasi setelah penulisan ke search cluster selesai → pemeliharaan indeks akan memberikan backpressure ke setiap producer
→ berikan konfirmasi penerimaan setelah melakukan commit ke durable stream yang direplikasi.
- Mengindeks setiap field JSON secara dinamis → kardinalitas tinggi menciptakan ledakan mapping (mapping explosion) dan biaya tak terkendali
→ indeks hanya field stabil yang masuk dalam daftar izin (allowlist).
- Menggunakan satu partisi stream per ID tenant → tenant besar akan menjadi bottleneck (hotspot) pada satu partisi
→ gunakan partisi virtual berdasarkan tenant dan sumber data, dengan pool khusus jika diperlukan.
- Mengklaim urutan global setelah pemartisian acak → jam mesin dan sumber paralel tidak dapat menyediakannya
→ pertahankan urutan lokal pada sumber data dan simpan timestamp observasi.
- Menggunakan exactly-once untuk menyembunyikan duplikat → respons yang hilang dan replay data tetap akan terjadi
→ gunakan pengiriman at-least-once, eventId yang stabil, dan penulisan yang idempoten.
- Mengasumsikan antrean tanpa batas dapat mencegah hilangnya data → disk, memori, dan batas retensi pada akhirnya akan penuh
→ tetapkan batas kapasitas, pantau usia pesan tertua, prioritaskan kelas log, dan simpan bukti data yang dibuang.
- Melakukan sampling pada semua log secara seragam selama lonjakan → bukti audit ikut terbuang
→ definisikan kebijakan keandalan dan degradasi secara terpisah berdasarkan kelas log.
- Menjanjikan setiap kueri selesai dalam 2 detik → pemindaian teks lengkap selama 90 hari akan membebani cluster interaktif
→ pisahkan kueri selektif di hot tier dari pemindaian historis asinkron.
- Menganggap hasil UI yang kosong sebagai bukti bahwa log tidak ada → keterlambatan pengindeksan menyembunyikan bukti insiden
→ tampilkan watermark, hasil parsial, dan rentang waktu yang belum terindeks.
- Hanya menghapus hot index saat retensi berakhir → arsip, cache, dan salinan ekspor masih menyimpan data sensitif
→ gunakan alur kerja penghapusan yang dapat diaudit di semua salinan data.
- Hanya memantau apakah proses Collector masih berjalan → proses yang sehat mungkin tetap membuang data
→ rekonsiliasi jumlah data antar-tahap dan pantau antrean, penolakan, serta kegagalan permanen.
Pertanyaan Lanjutan dan Tanggapan
Pertanyaan lanjutan 1: Mengapa tidak membiarkan agent menulis langsung ke search cluster?
Pendekatan itu masuk akal untuk sistem internal kecil karena memiliki lebih sedikit komponen dan pembaruan pencarian langsung. Namun pada skala ini, perubahan shard pencarian, kegagalan mapping, dan penolakan penulisan akan berdampak langsung pada 100.000 sumber. Durable stream menyediakan batas konfirmasi penerimaan, menyerap lonjakan traffic, memungkinkan konsumen pulih secara mandiri, dan mendukung replay data. Biayanya berupa operasi tambahan, potensi duplikasi, dan keterlambatan asinkron. Jika skala terukur masih kecil, pilihlah jalur langsung daripada menambahkan broker hanya untuk kebutuhan diagram.
Pertanyaan lanjutan 2: Bagaimana jika satu field tiba-tiba memiliki jutaan nilai yang berbeda?
Schema registry mencatat field yang dapat diindeks, tipe data, tim pemilik, dan batasan kardinalitas. Processor menggunakan penghitungan perkiraan nilai unik (approximate distinct counts) untuk mengawasi kardinalitas. Saat suatu field melewati batasnya, processor akan berhenti membuat struktur indeks baru, menyimpan nilainya sebagai atribut yang tidak diindeks, dan memberi tahu tenant terkait. Jika mapping explosion sudah terlanjur terjadi, pertama-tama blokir field baru dan perbaiki format di upstream, lalu bangun ulang field yang sehat ke dalam indeks baru. Membagi kumpulan field tak terbatas yang sama ke lebih banyak indeks tidak menyelesaikan masalah pertumbuhannya.
Pertanyaan lanjutan 3: Apa yang terjadi jika durable stream dan local spool sama-sama penuh?
Sistem yang terbatas tidak dapat menjamin penanganan lonjakan tanpa batas. Agent mencadangkan kapasitas berdasarkan kelas log: event audit menggunakan saluran paling andal, error lebih diprioritaskan daripada event informasi, dan log debug di-sample atau dibuang terlebih dahulu. Setiap data yang dibuang dihitung secara lokal dan dilaporkan setelah sistem pulih. Jika suatu operasi bisnis mengharuskan event audit tertentu tersimpan secara durable, operasi tersebut dapat digagalkan secara eksplisit atau menggunakan pola transactional outbox lokal. Pemanggilan log debug biasa tidak boleh memblokir seluruh aplikasi selamanya.
Pertanyaan lanjutan 4: Bagaimana cara membangun ulang search index dari object storage?
Objek arsip mencakup versi skema, partisi waktu, tenant, checksum, dan sebuah manifes. Tugas pembangunan ulang memilih tenant dan rentang waktu, membaca dan memverifikasi manifes, mentransformasi record dengan mapping saat ini, dan menulis ke indeks baru secara idempoten berdasarkan eventId. Sistem membandingkan jumlah data, batas waktu, dan data canary sebelum mengalihkan alias atau rute secara atomik. Traffic pembangunan ulang memiliki kuota terpisah agar tidak mengganggu pengindeksan real-time.
Pertanyaan lanjutan 5: Bagaimana cara mencegah kueri dari satu tenant mengganggu tenant lainnya?
Scheduler mengelola token bucket per tenant untuk konkurensi, waktu CPU, byte yang di-scan, dan baris yang dikembalikan, serta menggunakan antrean weighted fair queuing. Kueri interaktif lebih diprioritaskan daripada ekspor data, dan proses yang berat dapat dibatalkan atau dialihkan ke mode asinkron. Shared cache key mencakup ringkasan identitas tenant dan izin akses. Tenant besar atau yang memiliki regulasi ketat dapat dialokasikan ke pool indeks terisolasi, tetapi isolasi hanya dilakukan setelah menganalisis bottleneck agar tenant kecil tidak membuat terlalu banyak shard kecil.
Pertanyaan lanjutan 6: Mengapa log audit memerlukan kebijakan terpisah?
Log audit ada untuk membuktikan siapa yang melakukan apa dan kapan tindakan itu dilakukan. Sampling, konten yang dapat diubah, dan penghapusan oleh administrator biasa akan merusak tujuan tersebut. Log audit memerlukan skema yang lebih ketat, asal-usul (provenance) yang terotentikasi, pemeriksaan integritas, arsip immutable, pembatasan kueri, dan audit akses. Log ini tetap tunduk pada kebijakan penghapusan privasi dan legal hold, sehingga istilah "immutable" berarti jalur operasional biasa tidak dapat mengubahnya, bukan berarti alur kerja kepatuhan yang berwenang tidak dapat mengambil tindakan.
Pertanyaan lanjutan 7: Bagaimana Anda memperluas desain ini ke lintas region?
Setiap region pertama-tama menulis event lokal ke dalam durable stream dan arsip lokal agar request bisnis tidak perlu menunggu transmisi lintas benua. Event membawa ID region dan ID tenant global, dan control plane mendistribusikan skema, kuota, serta aturan retensi. Global query coordinator menyebarkan kueri (fan-out) berdasarkan waktu dan region, serta menandai hasil parsial jika suatu region tidak tersedia. Jika regulasi mewajibkan lokalisasi data (data residency), log mentah tetap berada di region lokal dan hanya indeks atau ringkasan yang disetujui yang boleh melintasi region. Pemulihan bencana (disaster recovery) dilakukan dari arsip objek lokal atau arsip yang direplikasi secara patuh regulasi.
Pertanyaan lanjutan 8: Bagaimana Anda membuktikan bahwa sistem tidak kehilangan log secara tersembunyi (silent loss)?
Setiap batch mencatat jumlah sumber dan checksum. Setiap tahap memancarkan metrik jumlah data yang diterima, duplikat, ditolak, gagal permanen, dan berhasil diproses. Canary unik secara terus-menerus dikirim melewati agent, gateway, durable stream, indeks, dan arsip. Rekonsiliasi memperbolehkan duplikat yang dapat dijelaskan oleh eventId dan data terbuang yang dapat dijelaskan oleh kebijakan kuota eksplisit. Setiap perbedaan data yang tidak dapat dijelaskan dianggap sebagai insiden. Kemudian, hentikan proses indexing selama 30 menit lalu pulihkan kembali, untuk memverifikasi bahwa usia pesan menurun, data canary mengisi jeda yang hilang, dan watermark kesegaran UI pulih seperti semula, alih-alih hanya memeriksa apakah prosesnya berhasil di-restart.