Selamat, kamu sudah menempuh seluruh perjalanan: dari task-tracker-api satu instance dengan SQLite, sampai tiga instance di belakang load balancer, dengan Postgres, Redis, dan observability lengkap. Di artikel penutup ini, kita rangkum kesalahan umum yang sering dilakukan pemula (dan kadang tim berpengalaman sekalipun), checklist debug untuk sistem yang lambat, dan ke mana kamu bisa melangkah lebih jauh.
Kesalahan Umum
Scaling tanpa mengukur dulu. Ini tema yang kita ulang sepanjang seri — kesalahan paling mahal adalah menambah kompleksitas (cache, instance, database baru) berdasarkan tebakan. Kita sendiri hampir salah simpul di Bagian 7 kalau tidak mengecek docker stats dan menemukan bottleneck-nya ternyata di alat ukur kita sendiri.
Menambah instance tanpa memastikan aplikasi benar-benar stateless. Kalau ada state penting tersimpan di memori satu instance (session, cache lokal, file upload sementara), horizontal scaling akan menghasilkan bug yang aneh dan sulit direproduksi — muncul random tergantung instance mana yang kebetulan menjawab.
Menandai async def tapi memanggil kode blocking di dalamnya. Sudah dibahas tuntas di Bagian 6 — ini lebih buruk daripada tetap pakai def biasa, karena membekukan seluruh event loop, bukan cuma satu thread.
Cache tanpa strategi invalidasi yang jelas. TTL saja bukan strategi invalidasi — cuma jaring pengaman. Tanpa invalidasi eksplisit saat data berubah (Bagian 4), user akan melihat data basi, dan bug seperti ini sering baru ketahuan setelah user komplain.
Index sembarangan, atau tidak index sama sekali. Tanpa index di kolom yang sering di-filter, query scaling linear dengan ukuran tabel (Bagian 5) — masalah yang sering baru terasa parah pas data sudah besar dan sudah terlambat untuk cepat diperbaiki. Sebaliknya, index di semua kolom juga bukan solusi — ada trade-off ke kecepatan tulis dan storage.
Metric dengan cardinality tinggi. Memakai raw path/ID sebagai label metric (Bagian 8) bisa meledakkan jumlah time series dan membuat sistem monitoring sendiri yang justru jadi lambat/mahal.
Tidak pernah menguji skenario kegagalan. Kita membangun load balancer supaya tidak ada single point of failure di lapisan aplikasi — tapi kalau tidak pernah benar-benar dites (matikan satu instance, lihat apakah trafik tetap jalan), itu klaim yang belum terbukti, cuma asumsi desain.
Checklist Debug Sistem yang Lambat di Production
Kalau sistem kamu melambat dan bingung mulai dari mana, ikuti urutan yang sudah kita praktikkan sepanjang seri ini:
Cek metrics dulu (Bagian 8) — endpoint mana yang p95-nya naik? Status code 5xx naik? Instance tertentu jauh lebih sibuk dari yang lain?
Cek resource usage di SEMUA pihak, termasuk alat ukur/klien kalau sedang load testing (Bagian 7) — jangan asumsikan bottleneck-nya pasti di server.
Baca log terstruktur untuk request spesifik yang lambat/gagal, pakai request_id untuk menelusuri jejaknya.
Cek apakah ini masalah I/O atau CPU (Bagian 1) — solusinya beda total.
Cek connection pool (database, dan kalau ada, HTTP client ke service lain) — error timeout yang berulang biasanya tanda pool kehabisan slot (Bagian 5).
Cek thread pool kalau endpoint-nya def biasa dan concurrency tinggi (Bagian 6) — bottleneck yang gampang terlewat karena tidak muncul sebagai error eksplisit.
Cek query plan (EXPLAIN ANALYZE) untuk query yang dicurigai lambat — cari Seq Scan yang mestinya Index Scan.
Roadmap Lanjutan
Seri ini sengaja fokus ke fondasi: caching, database, concurrency, horizontal scaling, observability. Kalau mau melangkah lebih jauh, berikut beberapa arah:
Message queue (RabbitMQ, SQS, Kafka) — untuk pekerjaan yang tidak perlu selesai sebelum response dikirim (kirim email, generate laporan besar), dipindah ke background worker lewat antrean, supaya endpoint API tetap responsif.
Read replica & database sharding — begitu satu instance Postgres sendiri jadi bottleneck (bukan lagi soal pool atau index), langkah berikutnya memisahkan beban baca ke replica, atau memecah data ke beberapa database (sharding) untuk skala yang jauh lebih besar.
Async database driver penuh (asyncpg, SQLAlchemy async) — migrasi task-tracker-api supaya benar-benar async def end-to-end, bukan cuma endpoint blocking dengan thread pool yang diperbesar seperti "obat sementara" di Bagian 6.
Prometheus + Grafana sungguhan — menghubungkan endpoint /metrics yang sudah kita bangun ke server Prometheus asli dan dashboard Grafana, plus alerting otomatis kalau metric melewati ambang batas tertentu.
Rate limiting & circuit breaker — melindungi sistem dari beban berlebih (baik dari user nakal maupun bug di client), dan mencegah satu service yang bermasalah menyeret seluruh sistem ikut down.
Container orchestration (Kubernetes) — begitu Docker Compose (yang cocok untuk belajar dan single-machine) tidak cukup lagi, Kubernetes menyediakan auto-scaling, self-healing, dan deployment strategy yang lebih canggih di banyak mesin sekaligus.
CDN untuk asset statis — kalau aplikasi punya asset statis (gambar, file, frontend build), CDN menyerap beban itu jauh sebelum sampai ke server aplikasi.
Menyambungkan ke pipeline CI/CD — kalau belum, seri CI/CD for Beginners membahas cara mengotomasi test dan deployment, supaya perubahan seperti yang kita buat sepanjang seri ini (index baru, pool size, kode aplikasi) bisa di-deploy dengan aman dan konsisten.
Kaitan dengan Seri Lain
Seri ini melanjutkan langsung task-tracker-api dari FastAPI for Beginners — kalau ada bagian yang terasa asing (path operation, dependency injection, Pydantic model), kemungkinan itu dasar yang dibahas di sana. Dan begitu API-mu scalable, otomasi build-test-deploy-nya ada di CI/CD for Beginners — ketiga seri ini dirancang saling melengkapi, mengikuti satu perjalanan yang sama dari nol sampai siap production.
Penutup
Kita sudah menempuh perjalanan dari "kenapa aplikasi berhenti scale", memahami anatomi sistem yang scalable, mengukur baseline, caching, database scaling, concurrency di dalam satu proses, horizontal scaling dengan Docker dan load balancer, sampai observability untuk tahu kapan harus scale lagi. Yang paling penting, setiap klaim di seri ini didukung angka nyata yang kita ukur sendiri — termasuk saat angkanya mengejutkan atau tidak sesuai ekspektasi awal, karena itulah inti dari scalability yang sesungguhnya: keputusan berdasarkan data, bukan tebakan.
Terima kasih sudah mengikuti seri Scalability for Beginners ini. Selamat mencoba di sistem kamu sendiri — dan selalu ukur dulu, baru optimasi.