21 poin oleh GN⁺ 2025-10-27 | Belum ada komentar. | Bagikan ke WhatsApp
  • Nanit menggunakan AWS S3 dalam pipeline pemrosesan video untuk analisis tidur bayi, tetapi dengan ribuan upload per detik, biaya permintaan PutObject menjadi porsi terbesar dari total biaya
  • Selain itu, karena batas retensi minimum 1 hari pada aturan S3 Lifecycle, untuk video yang sebenarnya diproses dalam 2 detik, mereka tetap harus membayar biaya penyimpanan 24 jam
  • Untuk mengatasinya, mereka membangun N3, sistem penyimpanan in-memory berbasis Rust, dan menggunakan S3 hanya sebagai buffer overflow
  • N3 sepenuhnya kompatibel dengan pipeline pemrosesan yang ada melalui SQS FIFO, sambil tetap mempertahankan jaminan urutan yang ketat dan keandalan
  • Hasilnya, mereka menghemat sekitar $500.000 per tahun sekaligus mendapatkan arsitektur yang sederhana dan stabil

Latar belakang

Gambaran pipeline pemrosesan video

  • Kamera Nanit merekam potongan video, meminta S3 presigned URL dari Camera Service, lalu mengunggah langsung ke S3
  • AWS Lambda memublikasikan object key ke antrian SQS FIFO (dishard berdasarkan baby_uid), lalu pod pemrosesan video mengonsumsinya dari SQS, mengunduh dari S3, dan menjalankan inferensi status tidur
  • Keuntungan dari pengaturan ini
    • Landing di S3 + antrean SQS memisahkan upload kamera dan pemrosesan video, sehingga mencegah kehilangan video bahkan selama pemeliharaan atau downtime sementara
    • Tidak perlu mengelola availability dan durability sendiri berkat S3
    • SQS FIFO + group ID menjaga urutan per bayi, dan node pemrosesan bisa tetap sebagian besar stateless
    • Aturan S3 Lifecycle menangani garbage collection sehingga tidak perlu melacak video yang sudah diproses

Mengapa perlu diubah

  • Biaya PutObject mendominasi: video adalah objek berumur sangat pendek yang hanya singgah selama beberapa detik sebelum diproses, tetapi pada skala ribuan upload per detik, biaya permintaan per objek menjadi pendorong biaya terbesar
    • Jika frekuensi chunking ditingkatkan (mengirim lebih banyak chunk kecil) demi menurunkan latensi, maka setiap chunk tambahan berarti satu permintaan PutObject lagi, sehingga biaya naik secara linear
  • Penyimpanan menjadi pajak kedua: walaupun pemrosesan selesai dalam sekitar 2 detik, aturan penghapusan Lifecycle tetap mengenakan biaya penyimpanan sekitar 24 jam
  • Mereka membutuhkan desain yang bisa menghindari biaya per objek di jalur normal sambil tetap menjaga keandalan dan jaminan urutan yang ketat, serta meminimalkan penyimpanan yang “membayar biaya saat menunggu”

Rencana

  • Prinsip desain

    • Kesederhanaan melalui arsitektur: menghilangkan kompleksitas di tingkat desain, bukan lewat implementasi yang terlalu cerdas
    • Ketepatan: menjadi pengganti penuh yang transparan bagi bagian pipeline lainnya
    • Dioptimalkan untuk jalur normal: dirancang untuk kasus umum, dan menggunakan S3 sebagai jaring pengaman untuk edge case; karena algoritme pemrosesan tahan terhadap jeda sesekali, kesederhanaan diprioritaskan daripada membangun jaminan yang kompleks
  • Pendorong desain

    • Objek berumur pendek: segmen hanya berada di area landing selama beberapa detik
    • Urutan: sequencing ketat per bayi (tidak memproses data yang lebih baru lebih dulu)
    • Throughput: ribuan upload per detik, 2-6 MB per segmen
    • Keterbatasan klien: kamera memiliki jumlah retry terbatas, jadi tidak bisa mengandalkan retransmisi
    • Operasional: harus bisa menoleransi backlog jutaan item selama pemeliharaan/scale-up
    • Tanpa perubahan firmware: harus bekerja dengan kamera yang sudah ada
    • Toleransi kehilangan: celah yang sangat kecil dapat diterima dan ditutupi oleh algoritme
    • Biaya: menghindari biaya S3 per objek di jalur normal dan meminimalkan penyimpanan “membayar biaya saat menunggu”

Gambaran desain (jalur normal N3 + overflow S3)

  • Arsitektur

    • N3 adalah area landing kustom yang menyimpan video di memori hanya selama waktu yang dibutuhkan untuk menguras pemrosesan (sekitar 2 detik), dan S3 hanya dipakai ketika N3 tidak mampu menangani beban
    • Dua komponen
      • N3-Proxy (stateless, antarmuka ganda)
        • eksternal (terhubung ke internet): menerima upload kamera melalui presigned URL
        • internal (privat): menerbitkan presigned URL ke Camera Service
      • N3-Storage (stateful, khusus internal): menyimpan segmen yang diunggah di RAM dan mengantrekan ke SQS dengan download URL yang dapat dialamatkan ke pod
    • Pod pemrosesan video mengonsumsi dari SQS FIFO dan mengunduh dari storage yang ditunjuk URL tersebut (N3 atau S3)
  • Alur normal (Happy Path)

    • Kamera meminta upload URL dari Camera Service
    • Camera Service meminta presigned URL dari API internal N3-Proxy
    • Kamera mengunggah video ke endpoint eksternal N3-Proxy
    • N3-Proxy meneruskannya ke N3-Storage
    • N3-Storage menyimpan video di memori dan mengantrekan ke SQS dengan download URL yang menunjuk ke dirinya sendiri
    • Pod pemrosesan mengunduh dari N3-Storage lalu memprosesnya
  • Fallback dua tingkat

    • Tier 1: fallback tingkat proxy (per permintaan)
      • Jika N3-Storage tidak bisa menerima upload karena tekanan memori, backlog pemrosesan, kegagalan pod, dan sebagainya, N3-Proxy akan mengunggah ke S3 atas nama kamera
      • Kamera sudah telanjur menerima URL N3 sebelum kegagalan terdeteksi
    • Tier 2: rerouting tingkat cluster (seluruh trafik)
      • Jika N3-Proxy atau N3-Storage tidak sehat, Camera Service akan berhenti menerbitkan URL N3 dan langsung mengembalikan S3 presigned URL
      • Seluruh trafik akan mengalir ke S3 sampai N3 pulih
  • Mengapa dipisah menjadi dua komponen

    • Blast radius: jika storage crash, proxy masih bisa merutekan ke S3; jika proxy crash, hanya trafik node itu yang terdampak, seluruh cluster storage tetap aman
    • Profil resource: proxy intensif CPU/jaringan (terminasi TLS), storage intensif memori (menahan video), sehingga membutuhkan tipe instance dan skala yang berbeda
    • Keamanan: storage tidak pernah bersentuhan dengan internet
    • Keamanan rollout: saat memperbarui proxy (stateless), storage (yang memegang data aktif) tidak disentuh

Validasi desain

  • Hal yang perlu divalidasi

    • Kapasitas dan sizing: durasi upload nyata di berbagai jaringan klien, compute yang dibutuhkan, dan ukuran buffer upload
    • Model storage: apakah semuanya bisa disimpan di RAM atau perlu disk
    • Resiliensi: bagaimana melakukan load balancing dengan murah dan menangani node gagal
    • Kebijakan operasional: kebutuhan GC, ekspektasi retry, dan apakah hapus saat GET sudah cukup
    • Unknown unknowns: edge case apa yang akan muncul saat ide ini bertemu dunia nyata
  • Pendekatan 1: stress test sintetis

    • Membangun load generator yang mendorong sistem hingga batasnya dengan berbagai concurrency, klien lambat, beban berkelanjutan, dan downtime pemrosesan
    • Tujuan: menemukan titik batas, mengidentifikasi bottleneck tak terduga, dan mendapatkan baseline deterministik untuk perencanaan kapasitas
  • Pendekatan 2: PoC produksi (mode mirror)

    • Uji sintetis tidak bisa mereplikasi perilaku kamera nyata: Wi‑Fi tidak stabil, berbagai versi firmware, dan kondisi jaringan yang tak terduga
    • Mode mirror: n3-proxy lebih dulu menulis ke S3 (retensi produksi), lalu juga menulis ke N3-Storage PoC (terhubung ke SQS canary + pemroses video)
    • Cohort target: berdasarkan versi firmware / daftar Baby-UID
    • Data parity: membandingkan status tidur antara PoC dan produksi, lalu menyelidiki perbedaannya
    • Observability: dashboard per jalur (N3 vs S3), kedalaman antrean, latensi/RPS, error budget, analisis egress
    • Feature flag (menggunakan Unleash) sangat penting: memungkinkan peralihan cohort secara real time tanpa deploy, menguji irisan sempit (firmware lama, kamera dengan Wi‑Fi lemah), lalu langsung memulihkan jika ada masalah
  • Temuan

    • Bottleneck: terminasi TLS menghabiskan sebagian besar CPU, dan AWS burstable networking mengalami throttling setelah kredit habis
    • Storage khusus memori layak dijalankan: distribusi waktu upload dan concurrency nyata menunjukkan working set bisa disimpan aman di RAM dengan margin, jadi disk tidak diperlukan
    • Overhead TCP timestamp: sekitar 85% dari total byte yang ditransmisikan adalah frame ACK; menonaktifkan TCP timestamp (sysctl -w net.ipv4.tcp_timestamps=0) menghemat 12 byte per ACK
      • Risiko: saat mengirim banyak byte pada soket yang sama, nomor urut bisa wrap sehingga paket tertunda bisa salah digabung dan menyebabkan korupsi
      • Mitigasi: (1) soket baru untuk setiap upload, (2) mendaur ulang soket n3-proxy ↔ n3-storage setelah sekitar 1 GB transfer
    • Kebocoran memori: setelah rilis awal, memori n3-proxy terus meningkat
      • Profiling jemalloc menunjukkan pertumbuhan pada buffer hyper BytesMut per koneksi
      • Beberapa koneksi klien berhenti di tengah transfer dan tidak dibersihkan, membuat buffer tertinggal dan memori terus naik
      • Perbaikan: membuat soket berumur pendek dan menerapkan batas waktu
        • Menonaktifkan keep-alive: koneksi langsung ditutup setelah setiap upload selesai
        • Memperketat timeout: menetapkan timeout header/soket untuk menghentikan upload yang macet dan membebaskan buffer

Storage

  • Storage in-memory

    • Memulai dari jalur paling sederhana: storage in-memory untuk menghindari tuning I/O dan memakai struktur data yang intuitif
    • Menyimpan video dengan Arc<DashMap<Ulid, Bytes>>; setiap upload video menaikkan bytes_used, dan setiap download menghapus video lalu menurunkannya
    • Mulai menolak upload saat kapasitas mencapai sekitar 80% atau lebih untuk menghindari OOM, dan memberi sinyal ke n3-proxy agar berhenti menandatangani upload URL
    • Tersedia handle control untuk menjeda upload dan garbage collection secara manual
  • Restart yang graceful

    • Karena storage hanya ada di memori, perlu mencegah data aktif hilang saat restart
    • Proses restart graceful
      • Pod menerima SIGTERM (StatefulSet rolling satu per satu)
      • Pod menjadi Not Ready dan keluar dari Service (tidak ada upload baru)
      • Tetap melayani download untuk video yang sudah telanjur diunggah
      • Saat download berhenti (tidak ada pembacaan baru belakangan ini → pemrosesan sudah terkuras)
      • Menunggu semua permintaan terbuka selesai
      • Setelah restart, lanjut ke pod berikutnya
    • Dalam kondisi normal, pod akan terkuras dalam beberapa detik
  • GC

    • Menggunakan dua mekanisme pembersihan
      • Hapus saat download: video dihapus tepat setelah diunduh; PoC menunjukkan nol re-download, dan karena pemroses video melakukan retry secara internal, tidak perlu menyimpan data atau melacak status “sudah diproses”
      • TTL GC untuk yang tertinggal: hapus saat download tidak mencakup segmen yang dilewati pemroses (tidak diunduh → tidak dihapus)
        • Ditambahkan TTL GC ringan: memindai DashMap in-memory secara berkala dan menghapus entri yang lebih tua dari ambang yang dapat dikonfigurasi (misalnya beberapa jam)
    • Mode pemeliharaan: selama downtime pemrosesan terencana, GC bisa dijeda melalui kontrol internal agar video tidak terhapus saat konsumsi berhenti

Kesimpulan

  • Hasil utama

    • Dengan menggunakan S3 sebagai buffer fallback dan N3 sebagai area landing utama, mereka berhasil menghemat sekitar $500.000 per tahun sambil menjaga sistem tetap sederhana dan andal
    • Insight utama: kebanyakan keputusan “build vs buy” berfokus pada fitur, tetapi pada skala besar, faktor ekonomi mengubah perhitungannya
      • Untuk objek berumur pendek (sekitar 2 detik dalam operasi normal), replikasi atau durability canggih tidak diperlukan; storage in-memory sederhana sudah cukup
      • Saat pemrosesan tertunda atau pemeliharaan memperpanjang umur objek, barulah diperlukan jaminan keandalan S3
      • Keunggulan kedua sisi: N3 menangani jalur normal secara efisien, S3 menyediakan durability saat objek perlu hidup lebih lama
      • Jika ada masalah pada N3 (tekanan memori, pod crash, masalah cluster), upload akan fail over ke S3 dengan mulus
  • Faktor keberhasilan

    • Mendefinisikan masalah dengan jelas sejak awal: kendala, asumsi, dan batasan mencegah scope creep
    • Validasi dini lewat PoC mode mirror: menemukan bottleneck (TLS, throttling jaringan) dan memverifikasi asumsi sebelum commit
      • Mencegah over-engineering dan backtracking
  • Kapan layak membangun hal seperti ini

    • Pertimbangkan infrastruktur kustom saat ada skala yang cukup untuk menghasilkan penghematan biaya yang berarti, dan ketika kendala spesifik memungkinkan solusi sederhana
    • Upaya engineering untuk membangun dan merawat sistem harus lebih kecil daripada biaya infrastruktur yang dihilangkan
    • Dalam kasus Nanit, kebutuhan spesifiknya (penyimpanan sementara, toleransi kehilangan, fallback S3) memungkinkan mereka membangun sesuatu yang cukup sederhana sehingga biaya pemeliharaannya tetap rendah
    • Jika kedua faktor itu tidak ada, tetaplah menggunakan managed service
    • Apakah akan dilakukan lagi? Ya, sistem ini berjalan stabil di produksi, dan desain fallback memungkinkan mereka menghindari kompleksitas tanpa mengorbankan keandalan

Belum ada komentar.

Belum ada komentar.