96 poin oleh GN⁺ 2025-08-18 | Belum ada komentar. | Bagikan ke WhatsApp
  • Desain sistem yang baik adalah bentuk yang tidak tampak rumit dan tidak menimbulkan masalah berarti dalam jangka waktu lama
  • Bagian tersulit dalam desain sistem adalah menangani state, dan penting untuk mengurangi sebanyak mungkin jumlah komponen yang menyimpan state
  • Database pada dasarnya adalah tempat state disimpan, sehingga diperlukan pendekatan yang berfokus pada desain skema dan pengindeksan, serta penghilangan bottleneck
  • Caching, pemrosesan event, dan pekerjaan latar belakang perlu diperkenalkan dengan hati-hati demi performa dan kemudahan pemeliharaan, dan sebaiknya tidak digunakan secara berlebihan
  • Daripada desain yang rumit, menggunakan komponen dan metodologi sederhana yang sudah cukup teruji dengan tepat adalah kunci untuk membangun sistem yang berkelanjutan dan stabil

Definisi desain sistem dan pendekatan secara keseluruhan

  • Jika desain perangkat lunak adalah perakitan kode, maka desain sistem adalah proses menggabungkan berbagai layanan
  • Komponen utama dalam desain sistem meliputi app server, database, cache, queue, event bus, proxy dan lain-lain
  • Desain yang baik memunculkan respons seperti "tidak ada masalah khusus", "selesai lebih mudah dari perkiraan", atau "bagian ini tidak perlu terlalu dipikirkan"
  • Sebaliknya, desain yang rumit dan mencolok bisa menyembunyikan masalah mendasar atau menunjukkan overengineering
  • Daripada langsung menerapkan sistem yang kompleks sejak awal, lebih menguntungkan untuk berkembang secara bertahap dari struktur sederhana minimal yang bisa berjalan

Membedakan state dan stateless

  • Bagian paling sulit dalam desain perangkat lunak adalah pengelolaan state
  • Layanan yang tidak menyimpan informasi dan langsung mengembalikan hasil (seperti rendering PDF GitHub) bersifat stateless
  • Sebaliknya, layanan yang melakukan penulisan ke database mengelola state
  • Sebaiknya kurangi sebanyak mungkin komponen penyimpan state dalam sistem. Ini menurunkan kompleksitas sistem dan kemungkinan terjadinya gangguan
  • Struktur yang disarankan adalah hanya satu layanan yang menangani state, sementara layanan lain berfokus pada peran stateless seperti pemanggilan API atau pemicu event

Desain database dan titik bottleneck

Desain skema dan indeks

  • Untuk penyimpanan data, diperlukan desain skema yang mudah dibaca manusia
  • Skema yang terlalu fleksibel (misalnya menyimpan semuanya dalam kolom JSON) bisa membebani kode aplikasi dan performa
  • Indeks yang tepat perlu ditetapkan berdasarkan kolom yang akan sering di-query. Memberi indeks pada semuanya justru menimbulkan overhead yang tidak perlu

Cara mengatasi bottleneck

  • Akses database sering menjadi bottleneck yang berat
  • Sebisa mungkin, data yang kompleks lebih menguntungkan diproses di dalam database dengan JOIN dan sejenisnya daripada di aplikasi
  • Saat menggunakan ORM, perlu berhati-hati agar tidak membuat query di dalam loop
  • Jika perlu, memecah query untuk mengatur beban database atau kompleksitas query juga bisa menjadi salah satu cara
  • Strategi mendistribusikan query baca ke read-replica efektif untuk mengurangi beban node utama (Write)
  • Ketika query dalam jumlah besar datang sekaligus, transaksi dan operasi tulis dapat dengan mudah membuat database kelebihan beban, sehingga perlu mempertimbangkan query throttling (pembatasan)

Memisahkan pekerjaan lambat dan pekerjaan cepat

  • Pekerjaan yang berinteraksi dengan pengguna perlu merespons dalam ratusan milidetik
  • Untuk pekerjaan yang memakan waktu lama (misalnya konversi PDF berukuran besar), pola yang efektif adalah memberikan hanya pekerjaan minimum secara langsung di frontend dan menyerahkan sisanya ke latar belakang
  • Pekerjaan latar belakang umumnya berjalan dengan kombinasi queue (misalnya Redis) dan job runner
  • Untuk pekerjaan yang dijadwalkan jauh di masa depan, bentuk yang praktis adalah mengelolanya lewat tabel DB terpisah alih-alih Redis, lalu mengeksekusinya dengan scheduler

Caching

  • Caching membantu mengurangi biaya dan meningkatkan performa ketika operasi yang sama atau mahal diulang berkali-kali
  • Biasanya engineer junior yang baru belajar cache ingin men-cache semuanya, sedangkan engineer berpengalaman lebih berhati-hati dalam memperkenalkan cache
  • Cache memperkenalkan state baru, sehingga ada risiko isu sinkronisasi/error/stale data
  • Lebih baik terlebih dahulu mencoba peningkatan performa seperti menambahkan indeks pada query, lalu menerapkan caching
  • Untuk cache berkapasitas besar, selain Redis/Memcached, pendekatan menyimpan secara berkala ke document storage seperti S3/Azure Blob Storage juga dapat digunakan

Pemrosesan event

  • Sebagian besar perusahaan memiliki event hub (misalnya Kafka), dan berbagai layanan diproses secara terdistribusi berbasis event
  • Daripada menggunakan event secara berlebihan, desain API request–response yang sederhana lebih berguna untuk logging dan pemecahan masalah
  • Pemrosesan berbasis event cocok ketika pengirim tidak perlu memedulikan perilaku penerima, atau untuk skenario berkapasitas tinggi dan toleran terhadap latensi

Cara penyampaian data: push dan pull

  • Dalam penyampaian data ada dua cara: Pull (request lalu response) dan Push (dikirim otomatis saat ada perubahan)
  • Metode Pull sederhana, tetapi bisa menimbulkan masalah permintaan berulang dan overload
  • Metode Push langsung mengirim data ke klien saat ada perubahan di server, sehingga lebih efisien dan menguntungkan untuk menjaga data tetap terbaru
  • Untuk menangani klien dalam jumlah besar, infrastruktur (queue event, beberapa server cache, dan sebagainya) perlu diperluas sesuai karakteristik masing-masing metode

Fokus pada hot path

  • Hot path berarti jalur paling penting dalam sistem dan tempat data mengalir paling banyak
  • Hot path memiliki sedikit pilihan, dan jika desainnya gagal dapat menimbulkan masalah serius pada seluruh layanan, sehingga desain yang hati-hati sangat penting
  • Daripada mengalokasikan sumber daya pada fitur minor dengan banyak opsi, lebih efektif untuk memusatkan desain dan pengujian pada hot path

Logging, metrik, dan pelacakan

  • Untuk mendiagnosis penyebab saat gangguan terjadi, perlu secara aktif mencatat log terperinci untuk jalur abnormal (unhappy path)
  • Diperlukan pengumpulan metrik observabilitas dasar seperti resource sistem (CPU/memori), ukuran queue, serta waktu request/pekerjaan
  • Alih-alih hanya melihat nilai rata-rata, metrik distribusi seperti latensi p95 dan p99 juga wajib diamati. Sejumlah kecil request yang lambat di bagian atas distribusi bisa menjadi masalah bagi pengguna utama

Kill switch, retry, dan pemulihan gangguan

  • Penggunaan kill switch (penghentian sementara sistem) dan strategi retry secara tepat sangat penting
  • Retry tanpa arah hanya akan membebani layanan lain, sehingga lebih efektif jika request terlebih dahulu dikendalikan dengan circuit breaker dan mekanisme serupa
  • Dengan menerapkan Idempotency Key, kita dapat mencegah pekerjaan duplikat saat request yang sama diproses ulang
  • Dalam beberapa situasi gangguan, perlu memilih antara fail open atau fail closed. Misalnya, untuk rate limiting, fail open (mengizinkan) memberi dampak lebih kecil bagi pengguna. Sebaliknya, autentikasi wajib fail closed

Penutup

  • Beberapa topik seperti pemisahan layanan, container, penerapan VM, dan tracing memang dihilangkan, tetapi menggunakan komponen yang sudah terbukti baik di tempat yang tepat pada akhirnya menghasilkan pembangunan sistem yang paling stabil dalam jangka panjang
  • Desain yang secara teknis terasa istimewa sebenarnya sangat jarang, dan desain yang sederhana sampai terasa membosankan justru paling sering digunakan dalam praktik
  • Pada dasarnya, desain sistem yang baik adalah proses menggabungkan metodologi yang tidak mencolok, aman, dan sudah cukup terbukti

Belum ada komentar.

Belum ada komentar.