Cara Mengurangi Latency pada Aplikasi Tanpa Mengorbankan Fitur

Semakin banyak fitur biasanya berarti semakin banyak dependency. Aplikasi mungkin bergantung pada database utama, Redis, search engine, payment provider, object storage, hingga beberapa internal API sekaligus.

Akibatnya, satu dependency yang lambat dapat ikut memperlambat seluruh pengalaman pengguna. Untungnya, optimasi tidak selalu berarti menghapus fitur.

Cara Mengurangi Latency pada Aplikasi dapat dilakukan dengan mengubah pola komunikasi, mengurangi pekerjaan pada request utama, serta membuat sistem lebih toleran terhadap dependency lambat.

Kuncinya adalah mengetahui ke mana waktu request dihabiskan, lalu memangkas waktu tunggu yang tidak memberikan nilai langsung kepada pengguna.

Buat Latency Budget untuk Setiap Dependency

Jika target response time endpoint adalah 500 ms, setiap dependency tidak boleh menggunakan waktu sesukanya.

Buat latency budget.

Misalnya:

API processing mendapat 100 ms, database 100 ms, external service 150 ms, sedangkan 150 ms sisanya menjadi margin untuk network dan overhead.

Pendekatan seperti ini membuat tim lebih disiplin dalam merancang critical path.

AWS menyarankan timeout pada setiap dependency call dan menekankan bahwa workload sebaiknya tidak menunggu dependency terlalu lama atau tanpa batas.

Pantau pula p95 dan p99 latency, bukan sekadar average.

Dependency dengan rata-rata 60 ms mungkin terlihat sehat, tetapi jika p99 mencapai dua detik, sebagian pengguna tetap akan mengalami response yang buruk.

Latency budget membuat kondisi tersebut lebih mudah terlihat.

Kurangi Panjang Synchronous Dependency Chain

Semakin panjang synchronous chain, semakin banyak titik yang harus selesai sebelum response bisa dikembalikan.

Misalnya:

API → Order → Customer → Inventory → Pricing → Promotion

Apabila setiap service harus menunggu service berikutnya, keseluruhan response time akan mengakumulasi waktu perjalanan tersebut.

AWS menyarankan meminimalkan jumlah dependency call untuk menyelesaikan satu request dan mengingatkan bahwa chatty communication meningkatkan coupling serta latency.

Tanyakan pada setiap dependency: apakah hasilnya benar-benar dibutuhkan sekarang?

Recommendation, analytics, notification, audit enrichment, atau secondary metadata sering dapat dikeluarkan dari synchronous flow.

Prinsipnya sederhana.

Synchronous hanya untuk pekerjaan yang menentukan hasil request. Sisanya dapat dipindahkan ke event atau background processing.

Dengan demikian fitur tetap tersedia, tetapi pengguna tidak harus menunggu semuanya selesai.

Manfaatkan Cache untuk Dependency yang Mahal

Bayangkan setiap request halaman produk harus mengambil data kategori dari database dan currency configuration dari remote service.

Jika datanya hampir tidak pernah berubah, call tersebut membuang waktu.

Microsoft menyebut No-Caching sebagai performance antipattern ketika aplikasi berulang kali mengambil informasi sama dari resource yang memiliki biaya I/O atau latency.

Caching bisa diterapkan pada beberapa layer.

Client atau CDN cocok untuk static content. Application cache cocok untuk data yang sering digunakan satu instance. Distributed cache berguna ketika banyak application instance perlu berbagi cached result.

Namun desain cache berdasarkan pola akses.

Data harga real-time mungkin membutuhkan TTL pendek, sedangkan daftar negara bisa bertahan berjam-jam.

Perhatikan pula risiko cache stampede.

Jika ribuan cache entry kedaluwarsa bersamaan, semua request bisa kembali menabrak database pada waktu yang sama.

Gunakan expiration jitter atau refresh secara bertahap agar pola tersebut lebih terkendali.

Reuse Connection daripada Membuatnya Berulang

Membuat koneksi baru memiliki biaya.

Database connection dapat membutuhkan network handshake, authentication, serta initialization. Jika aplikasi membuat koneksi baru pada setiap request, biaya kecil tersebut terus terakumulasi.

Microsoft merekomendasikan connection pooling untuk menggunakan kembali koneksi database yang sudah terbentuk. Teknik ini mengurangi connection latency dan mendukung throughput yang lebih tinggi.

Prinsip yang sama berlaku pada komunikasi HTTP.

Persistent connection atau connection reuse mengurangi kebutuhan membangun communication channel baru berulang kali.

Microsoft mencatat pendekatan tersebut dapat mengurangi network overhead dan meningkatkan responsiveness, meskipun jumlah koneksi tetap perlu dikelola agar tidak mengganggu scalability.

Jangan hanya mengaktifkan pool lalu melupakannya.

Pantau pool utilization, waiting requests, dan connection limit.

Pool yang terlalu kecil menciptakan antrian. Terlalu besar dapat membuat database menerima concurrency melebihi kapasitasnya.

Konfigruasi ideal perlu diuji berdasarkan traffic nyata.

Hindari Mengambil Data Berlebihan

Kadang developer mencoba mengurangi jumlah network call dengan mengambil semuanya sekaligus.

Strategi ini juga bisa salah.

Microsoft menyebut Extraneous Fetching sebagai kondisi ketika aplikasi mengambil lebih banyak data daripada yang diperlukan untuk suatu operasi, sehingga meningkatkan I/O dan menurunkan responsiveness.

Misalnya halaman daftar produk hanya membutuhkan nama, thumbnail, harga, dan rating.

Tidak perlu mengambil deskripsi panjang, riwayat stok, detail supplier, dan semua review hanya karena data tersebut tersedia.

Gunakan projection pada query database dan API.

GraphQL atau endpoint khusus juga dapat membantu ketika client mempunyai kebutuhan data yang berbeda, asalkan tidak menghasilkan N+1 query di backend.

Perhatikan payload size.

Mengurangi response dari 2 MB menjadi 200 KB akan mengurangi waktu transfer, serialization, deserialization, dan penggunaan memory.

Pada koneksi mobile, perbedaannya bisa terasa lebih signifikan.

Gunakan Asynchronous I/O agar Thread Tidak Banyak Menunggu

I/O biasanya lebih lambat daripada operasi CPU karena aplikasi harus menunggu database, network, storage, atau external API.

Jika thread diblokir selama masa tunggu tersebut, kapasitas aplikasi dapat turun ketika concurrency meningkat.

Microsoft menjelaskan bahwa synchronous I/O memblokir calling thread sampai proses I/O selesai dan dapat menurunkan performance serta vertical scalability.

Gunakan async/non-blocking I/O ketika platform mendukungnya.

Tujuannya bukan membuat external dependency menjadi lebih cepat.

Jika payment provider tetap membutuhkan 400 ms, async tidak akan mengubahnya menjadi 50 ms.

Manfaatnya adalah thread dapat mengerjakan request lain selama menunggu, sehingga aplikasi mampu menangani concurrency lebih tinggi.

Namun async bukan solusi ajaib.

Jika CPU sudah 100%, membuat lebih banyak asynchronous task hanya dapat meningkatkan contention.

Gunakan metrics untuk memastikan masalahnya memang berasal dari waiting I/O.

Kendalikan Retry agar Tidak Menambah Latency

Retry kadang meningkatkan reliability, tetapi juga dapat memperpanjang response time.

Bayangkan dependency memiliki timeout dua detik dan aplikasi melakukan tiga retry. Satu request dapat tertahan jauh lebih lama sebelum akhirnya gagal.

AWS menyarankan exponential backoff, jitter, serta maksimum retry. Retry pada banyak layer harus dihindari karena dapat saling mengalikan dan menghasilkan retry storm.

Tidak semua error perlu dicoba ulang.

HTTP 429 atau transient network issue mungkin cocok untuk retry sesuai aturan dependency. Error authentication karena credential salah biasanya tidak akan sembuh hanya dengan mengirim request yang sama lagi.

Pertimbangkan circuit breaker ketika dependency terus mengalami gangguan.

Fail fast terkadang menghasilkan user experience lebih baik daripada membuat pengguna menunggu beberapa detik hanya untuk menerima kegagalan yang sama.

Responce fallback seperti cached data atau fitur yang sementara disederhanakan juga dapat menjaga fungsi inti aplikasi tetap tersedia.

Gunakan Tracing untuk Mengetahui Dependency yang Paling Mahal

Optimasi tanpa observability mudah berubah menjadi tebakan.

Distributed tracing memungkinkan tim melihat berapa lama setiap dependency menghabiskan waktu di dalam request.

OpenTelemetry menggunakan context propagation untuk menghubungkan telemetry melintasi process dan network boundary, sehingga hubungan sebab-akibat antarlayanan dapat ditelusuri.

Contohnya total latency checkout mencapai 1,4 detik.

Trace menunjukkan:

database 120 ms, inventory 90 ms, shipping 140 ms, dan fraud detection 850 ms.

Data ini langsung mempersempit investigasi.

Tim dapat memeriksa apakah fraud detection perlu dipanggil synchronously, apakah result tertentu dapat di-cache, atau apakah timeout perlu diturunkan.

Observabilty juga membantu melihat perubahan setelah deployment.

Jika p95 tiba-tiba naik setelah versi baru dirilis, trace comparison dapat menunjukkan dependency atau operation yang berubah.

Ukur dahulu, optimalkan kedua, dan validasi hasilnya kembali.

Cara Mengurangi Latency pada Aplikasi tidak harus dilakukan dengan menghapus dependency atau fitur.

Bangun latency budget, pendekkan synchronous chain, gunakan caching, manfaatkan connection pooling, dan hindari pengambilan data berlebihan.

Kombinasikan timeout, retry, async I/O, serta tracing untuk menjaga critical path tetap cepat. Audit satu user journey penting hari ini dan cari dependency yang paling banyak menghabiskan waktu.