For the complete documentation index, see llms.txt. This page is also available as Markdown.

Cache

Dalam pengembangan aplikasi modern, caching adalah salah satu strategi paling efektif untuk meningkatkan performa dan mengurangi beban database. Buku ini akan memandu Anda melalui implementasi caching yang robust menggunakan Valkey (fork dari Redis).

📂 Kode Lengkap Bab Ini: Seluruh kode yang dibahas di bab ini tersedia di GitHub:

🔗 github.com/jacky-htg/workshop/tree/main/22-cache

22.1 Masalah yang Dihadapi

Bayangkan Anda memiliki aplikasi dengan fitur daftar pengguna (List Users) yang dipanggil ribuan kali per detik. Setiap request akan:

  1. Query database (SELECT * FROM users)

  2. Mengirimkan data ke user

  3. Memproses query yang sama berulang kali

Dampak:

  • Database overload

  • Response time lambat (100ms+)

  • Biaya infrastruktur tinggi

22.2 Solusi: Caching

Dengan caching, kita menyimpan hasil query di memory (Valkey/Redis) sehingga:

Metrik

Tanpa Cache

Dengan Cache

Response Time

100ms+

1-5ms

Database Load

100%

< 10%

Skalabilitas

Terbatas

Sangat baik

22.3 Memilih Cache Server

Redis banyak digunakan sebagai server cache, namnun semenjak redis tidak lagi open source, komunitas opensource membuat valkey yang di-fork dari redis versi 7.2.

Mnejalankan Valkey dengan Docker

22.4 Memilih Library Go untuk Valkey

Library
Kelebihan
Kekurangan

valkey-glide

Multi-language support (Rust core), AZ Affinity Routing (optimasi biaya cloud), Stable dan enterprise-ready, Consisten di semua bahasa

1 koneksi multiplex per node, Perlu client terpisah untuk operasi besar

valkey-go

Native Go, sangat cepat, Auto-pipelining, Client-side caching, Connection pool support

Hanya untuk Go, Fitur enterprise terbatas

Rekomendasi

  • Cloud (AWS/GCP) -> Gunakan valkey-glide (AZ Affinity routing menghemat biaya)

  • On premise -> Gunakan valkey-go (Lebih ringan).

22.5 Arsitektur Caching

Prinsip Dasar

Operasi terkait cache dihandle oleh Service Layer, bukan Handler atau Repository:

Cache-Aside Pattern

Cache-Aside adalah strategi caching paling umum. Aplikasi bertanggung jawab penuh mengelola cache:

22.6 Implementasi Cache Client

Interface Cache Client

Implementasi Standalone Valkey

Konfigurasi Cache

22.7 Helper List Cache (Key Registering)

Untuk cache dengan banyak parameter (seperti List Users dengan sorting, filtering, pagination), kita perlu strategi khusus untuk mengelola key. Masalah

Pada List Users, setiap kombinasi parameter menghasilkan key berbeda:

  • users::list::order:name::sort:asc::search:admin::limit:10::page:1

  • users::list::order:name::sort:desc::search:admin::limit:10::page:1

  • users::list::order:email::sort:asc::search:john::limit:20::page:2

Masalah pada Write Flow: Bagaimana menghapus semua key yang relevan saat data berubah?

Pendekatan yang umum digunakan ada 3:

  1. Cache dengan TTL pendek, sehingga tidak perlu dipusingkan bagaimana melakukan invalidate, karena cache secara otomatis expired ketika TTL habis. Kelemahannya adalah data cache tidak bisa dijamin merupakan data paling baru.

  2. Versioning Number. Dibuat cache untuk mengelola versioning dari setiap kelompok cache. Keuntungannya data cache selalu paling update, mudah diterapkan, dan tidak perlu dipusingkan dengan invalidate cache. Kelemahanya storage membengkak karena cache yang sudah tidak valid masih disimpan hingga TTL nya habis.

  3. Key Registering, dimana setiap key didaftarkan ke dalam index_list, sehingga key yang sudah tidak terpakai bisa dihapus. Keuntungan data cache tetap terbaru, storage tidak membengkak, namun kompleksitasnya tinggi.

Solusi: Key Registering dengan SET

Helper List Cache

Buat helper listcache dengan fungsi :

  • GenereateKey untuk konsistensi penamaan key cache

  • AddKeyToIndex untuk proses registering key

  • InvalidateListCache untuk proses invalidate cache

  • Cleanup untuk menghapus member key yang sudah expired

Buat file pkg/listcache/helper.go

22.8 Implementasi Cache di Service User

22.9 Mengatasi Masalah Cache

Cache Stampede

Masalah: Cache expired bersamaan → banyak request hit database simultaneously.

Solusi: Tambahkan jitter pada TTL:

Thundering Herd

Masalah: Banyak request konkuren untuk data yang sama → semua request database.

Solusi: Gunakan Single Flight Pattern (hanya 1 request ke database, sisanya menunggu):

Lebih detail terkait pattern single flight bisa dibaca di Single Flight Pattern.

Operasi Penghapusan Data yang Besar

Masalah: SMEMBERS + DEL untuk ribuan key bersifat blocking.

Solusi: Gunakan SSCAN untuk iterasi bertahap (sudah diimplementasikan di cleanupStaleIndexBatch).

Operasi Blocking di Valkey Glide

Masalah: Valkey Glide menggunakan multiplex yang unggul secara throughput namun lemah terhadap operasi blcoking seperti BLPOP atau penghapusan data yang besar.

Solusi:

  • On premise : gunakan valkey-go, dimana koneksi valkey otomatis dijalankan dengan multiplex untuk perintah nonblocking, namun perintah blocking akan dijalankan dengan koneksi pool connection.

  • Cloud AWS/GCP : buat dua koneksi client. Pilihan koneksi diset secara manual di dalam kode agar operasi blocking tidak menghambat operasi nonblocking. Jika operasi nonblocking gunakan koneksi A, semantara operasi blocking menggunakan koneksi B.

22.10 Update Bootstrap dengan Cache

Ringkasan Bab 22

Di bab ini kita telah belajar:

Komponen
Fungsi

Cache Client Interface

Abstraksi untuk berbagai implementasi cache

Valkey Standalone

Implementasi dengan valkey-glide

Cache-Aside Pattern

Strategi caching dengan invalidation manual

Key Registering

Mengelola cache dengan banyak parameter menggunakan SET

List Cache Helper

Generate key, add to index, invalidate, cleanup

Single Flight

Mencegah Thundering Herd

Manfaat yang kita peroleh:

  • ✅ Response time turun dari 100ms ke 1-5ms

  • ✅ Beban database berkurang 90%+

  • ✅ Cache terkelola dengan baik (invalidation otomatis)

  • ✅ Index management dengan SET (SADD, SMEMBERS, SSCAN, SREM)

  • ✅ Proteksi dari Cache Stampede dan Thundering Herd

Yang akan datang:

  • Saat ini kita belum memanggil API eksternal

  • Bab selanjutnya: Call API Third Party – memanggil service eksternal dengan retry, timeout, dan circuit breaker

Last updated