Caching
Memahami mekanisme yang membuat sistem backend berperforma tinggi jadi cepat, dari Google Search sampai Netflix dan Redis.
Apa Itu Caching?
Satu kalimat itu seluruh konsepnya diringkas. Tapi mari kita buka dengan benar karena implikasinya merembes ke seluruh engineering backend.
Definisi Dua Bagian
Ada dua cara memahami caching, versi bahasa polos dan versi teknis. Keduanya mengatakan hal yang sama persis, hanya pada tingkat presisi berbeda:
Caching adalah mekanisme yang kita pakai untuk mengurangi jumlah waktu dan usaha yang dibutuhkan melakukan sejumlah pekerjaan. Itulah penjelasan daring tentang apa sebenarnya caching.
Caching adalah menyimpan sebagian (subset) dari suatu data: anggap kita punya sumber data primer, saat kita menyimpan subset (bukan seluruh data, sebagian) dari data itu, tergantung kegunaan datanya, frekuensi pemakaiannya, probabilitas pemakaian berikutnya, waktu, dll., tergantung banyak parameter, kita menyimpan subset itu di lokasi yang lebih cepat diakses, yang memakan waktu lebih sedikit, dan juga usaha lebih sedikit. Jadi secara teknis, caching adalah mekanisme yang bisa kita pakai untuk mengurangi jumlah waktu dan usaha yang dibutuhkan mengambil atau melakukan semacam operasi.
Kenapa "Subset" Kata Terpenting
Definisinya bilang subset, bukan semua data, bukan salinan semuanya, melainkan bagian data primer yang dipilih dengan hati-hati. Ini kritis karena dua alasan:
- Caching lebih mahal daripada penyimpanan disk. Menyimpan data di cache (biasanya di RAM) jauh lebih mahal per gigabyte daripada menyimpan di hard disk atau SSD. Anda tidak mungkin mampu men-cache semuanya. Penyimpanan disk relatif lebih murah dan menawarkan banyak kapasitas, sebab itu kita tidak menaruh semuanya di memori cache.
- Kapasitas cache terbatas. RAM langka dibanding penyimpanan sekunder. Server khas mungkin punya 64GB atau 128GB RAM tapi beberapa terabyte disk. Anda harus selektif.
- Men-cache semuanya meniadakan tujuannya. Jika Anda men-cache semuanya, Anda cuma menduplikasi penyimpanan dengan biaya jauh lebih tinggi. Intinya men-cache hal yang tepat, data yang benar-benar akan diakses lagi segera.
Parameter yang Mengatur Apa yang Di-cache
Saat merancang lapisan caching, inilah parameter yang Anda evaluasi untuk memutuskan apa yang layak masuk cache:
- Frekuensi pemakaian: Seberapa sering data ini diakses? Data yang diakses ribuan kali per menit kandidat jauh lebih baik daripada data yang diakses sekali sehari.
- Probabilitas pemakaian berikutnya: Berdasarkan pola akses, seberapa besar kemungkinan statistik data ini diminta lagi segera? Model machine learning dipakai di skala besar (Netflix, Twitter) untuk memprediksi ini.
- Kebaruan (recency): Apakah data ini baru diakses? Data yang baru diakses secara statistik lebih mungkin diakses lagi segera (prinsip temporal locality).
- Biaya komputasi ulang: Seberapa mahal membuat ulang data ini jika tidak ada di cache? Pencarian DB sederhana murah. Komputasi ML trending-topics atas miliaran tweet sangat mahal. Semakin mahal komputasinya, semakin kuat alasan men-cache.
- Volatilitas data: Seberapa sering data ini berubah? Data yang sangat volatil (mis. harga saham langsung) kandidat caching yang buruk karena langsung basi. Data statis (deskripsi produk, profil pengguna) kandidat sangat baik.
Kenapa Caching Penting: Konteks Performa Tinggi
Satu mekanisme ini, caching, adalah faktor besar di banyak aplikasi berperforma tinggi. Saat kita bilang performa tinggi, maksudnya aplikasi yang melacak latensi dalam hitungan mikro detik dua digit atau milidetik. Di skala itu, selisih 5ms di waktu respons pun terasa, dan selisih 50ms tidak bisa diterima.
Tanpa caching, sistem lalu lintas tinggi menghadapi dua hambatan mustahil:
1. Komputasi berat: Saat menghasilkan hasil butuh sumber daya CPU, GPU, atau memori signifikan (inferensi ML, join kompleks lintas jutaan baris, pipeline agregasi). Anda tidak ingin mengulang ini untuk setiap request pengguna. 2. Transfer data berat: Saat data yang dikirim besar (file video, pustaka gambar, payload JSON besar) dan mengirimnya lewat jaringan untuk setiap request lambat dan mahal. Anda ingin data itu sudah dekat dengan pengguna.
Dua skenario ini, menghindari komputasi ulang yang mahal dan menghindari transfer data berat yang redundan, adalah pola yang akan Anda kenali di setiap kasus caching yang Anda temui sepanjang karier. Kapan pun Anda melihat salah satu dari dua situasi ini, insting pertama Anda harus: "Bisa kita cache ini?"
Contoh Dunia Nyata
Sebelum menyelami mekanikanya, membantu memahami kenapa caching penting di skala produksi. Mari lihat tiga contoh yang mengilustrasikan konsep dan dua skenario inti tempat caching selalu muncul. Setelah contoh-contoh ini, Anda akan mulai melihat polanya di mana-mana.
Contoh 1: Google Search
Hampir semua kita memakai atau pernah memakai Google Search di browser. Apa yang sebenarnya terjadi saat Anda mengetik sesuatu di bar pencarian Google dan menekan Enter?
Query itu diproses mesin pencari Google lewat algoritma dan alur kerja yang cukup rumit. Setiap query melewati pipeline yang biasanya melibatkan:
- Crawling: bot Google terus merayapi web, menemukan dan mengunduh miliaran halaman
- Indexing: konten yang dirayapi dianalisis dan ditambahkan ke index pencarian raksasa
- Ranking: saat query tiba, ratusan algoritma ranking menentukan hasil mana yang paling relevan
Seluruh proses ini mahal secara komputasi: saat kita bilang mahal, maksudnya mahal secara komputasi. Ia butuh banyak daya komputasi, banyak CPU, banyak sumber daya memori, dll.
Sekarang anggap query seperti "what is the weather today", query seperti ini dicari jutaan dan jutaan kali setiap hari. Tanpa caching, tanpa mengimplementasikan mekanisme bernama caching ini, server Google harus menghitung ulang semua hasil untuk setiap query. Setiap query yang melibatkan cuaca saat ini sebuah lokasi akan menuntut melewati seluruh index, menjalankan semua algoritma ranking, dan mengambil hasilnya, yang pada gilirannya memperlambat waktu respons secara signifikan dan menimbulkan beban server sangat tinggi.
Apa yang Dilakukan Google Sebagai Gantinya
Google memakai sistem caching terdistribusi di memori untuk menyimpan hasilnya. Kata kuncinya di sini terdistribusi, server sistem caching tersebar di seluruh dunia. Mereka tidak hanya terkonsentrasi di satu lokasi tapi tersebar di seluruh dunia, dan server cache itu menyimpan hasil, hasil apa pun yang dikembalikan semua algoritma ranking dan berbagai algoritma yang terlibat di seluruh alur kerja Google Search. Hasil itu di-cache atau disimpan di server-server ini.
Saat pengguna mencari, sistem pertama memeriksa apakah hasil query tertentu itu ada di cache atau tidak:
Mari telusuri kedua jalur secara presisi:
- Cache Hit: Jika query sudah pernah dicari (mis. "weather in Delhi" dicari 5 menit lalu oleh orang lain), sistem menemukannya di cache dan mengembalikan hasilnya seketika. Mengambil data dari cache sangat cepat, itulah salah satu alasan utama kita memakai cache.
- Cache Miss: Jika query tidak pernah dicari, atau cache kedaluwarsa, sistem melewati alur kerja penuh normal, semua ranking, semua sorting, algoritma apa pun yang terlibat. Lalu ia mengambil hasil itu, men-cache-nya, dan mengembalikannya ke pengguna. Jadi lain kali pengguna yang sama atau pengguna lain mengetik query yang sama, hasilnya bisa diambil langsung dari cache.
Cache Hit: Saat Anda mencari data di cache dan menemukannya. Jalur cepat. Tanpa komputasi ulang. Cache Miss: Saat Anda mencari data di cache dan ia tidak ada. Harus ke sumber primer, menghitung hasilnya, lalu menyimpannya untuk pemakaian masa depan.
Contoh 2: Netflix & CDN
Netflix platform streaming besar dan global yang mengirimkan berbagai jenis konten, film, serial, anime, dll., ke jutaan pengguna di seluruh dunia. Ia men-stream volume data besar, dan saat kita bilang besar, bisa beberapa terabyte, karena cara kerja platform streaming ini.
Cara Netflix Menyimpan Satu Film
Untuk satu video, katakanlah satu film bernama Movie One, ia melewati proses bernama encoding. Ia menyiapkan resolusi berbeda untuk perangkat berbeda dan kecepatan jaringan berbeda. Untuk penjelasan tingkat tinggi, katakanlah ia punya:
- 1080p, untuk internet cepat dan perangkat kelas atas
- 720p, untuk koneksi sedang
- 480p, untuk koneksi lambat atau data seluler
- dan lebih banyak format untuk codec dan perangkat berbeda
Tergantung kecepatan jaringan dan perangkat yang Anda pakai, Netflix secara dinamis mengirim versi yang dioptimalkan dari konten itu supaya Anda tidak membuang bandwidth dan beban di server Netflix juga turun. Itu semua soal encoding. Tapi pertanyaan sebenarnya: bagaimana Netflix benar-benar mengirim ratusan dan ribuan terabyte data ke jutaan pengguna yang tersebar di seluruh dunia, dengan buffering minimal?
Jawabannya: CDN (Content Delivery Network)
Netflix punya server origin-nya sendiri, katakanlah di suatu tempat di AS, di berbagai pusat data dan lokasi, dengan rak server yang menyimpan film-film aktualnya. Tapi Netflix melakukan langkah ekstra. Di seluruh dunia, di berbagai lokasi, Netflix menempatkan yang disebut Edge Location.
Mereka disebut Edge Location karena server ini ditempatkan strategis supaya latensi bagi pengguna di region itu minimal. Jika ada server di India, maka untuk pengguna India, latensi request data yang dilayani server itu minimal, dibanding semua request yang harus melewati server origin yang berada di AS.
Bayangkan apa yang terjadi tanpanya: semua orang di India yang ingin menonton film di Netflix akan mengirim request sampai ke pusat data AS. Secara geografis, itu jarak jauh bagi data untuk bepergian. Waktu respons tinggi, Anda akan mengalami buffering. Tapi dengan edge server di Mumbai atau Chennai, jarak itu runtuh mendekati nol.
Istilah kunci dari contoh ini, kosakata penting yang akan Anda pakai sepanjang karier:
- CDN (Content Delivery Network): Jaringan server terdistribusi global yang men-cache dan mengirimkan konten dari lokasi yang secara geografis lebih dekat ke pengguna akhir. Netflix punya CDN sendiri (disebut Open Connect). Penyedia CDN lain meliputi Cloudflare, Akamai, Fastly, AWS CloudFront.
- Edge Location / Edge Server / Edge Computing: Kapan pun Anda melihat kata "edge" dalam konteks infrastruktur, intinya ia server yang paling dekat dengan pengguna alih-alih server terpusat atau origin. "Edge" adalah tepi jaringan, dekat dengan pengguna akhir.
- PoP (Point of Presence): PoP cuma istilah keren yang intinya sebuah region tertentu tempat ada banyak edge server. Kumpulan banyak edge server yang terkonsentrasi di satu region disebut PoP. Misalnya, Netflix mungkin punya PoP di Mumbai yang terdiri dari 10-20 edge server.
- Originating Server: Server master/primer tempat data kanonis sebenarnya tinggal. Edge server mengambil konten dari sini, men-cache-nya lokal, dan melayani pengguna dari salinan mereka sendiri.
- TTL (Time to Live): Durasi yang dikonfigurasi pada konten ter-cache, setelah itu ia dianggap basi. Saat TTL kedaluwarsa, edge server harus mengambil ulang konten dari originating server untuk mendapat salinan segar. Perusahaan men-set "durasi wajar", konten ini sebaiknya hanya di-cache beberapa jam ke depan karena setelah itu mungkin ada versi baru.
Netflix tidak men-cache semua datanya di semua edge location. Itu biaya luar biasa dan butuh banyak sumber daya. Gantinya, mereka memakai algoritma machine learning, analisis tren, data regional waktu nyata, dan banyak komputasi rumit lain untuk memutuskan subset data apa yang di-cache di tiap edge location spesifik. Server di Mumbai mungkin men-cache film Bollywood populer dan acara India yang sedang tren, sementara server di Tokyo men-cache anime dan J-drama. Ini caching cerdas berbasis data regional, bukan replikasi paksa.
CDN bukan hanya untuk streaming video. Platform seperti Vercel memakai strategi yang sama persis untuk melayani aset web statis, bundel JavaScript, file HTML, CSS, gambar, dari edge terdekat dengan pengguna yang meminta. Saat Anda deploy aplikasi Next.js di Vercel, ia otomatis didistribusikan ke jaringan edge global mereka. Itulah kenapa deployment Vercel memuat hampir seketika di mana pun Anda berada di dunia. Prinsip sama, mekanisme sama, jenis konten berbeda.
Contoh 3: Twitter / X (Trending Topics)
Mari ambil platform bernama X, dulu dikenal sebagai Twitter. Anda bisa menerapkan contoh ini ke platform media sosial mana pun, Facebook, LinkedIn, YouTube, mereka semua mengimplementasikan strategi jenis yang sama.
Jika Anda familiar dengan cara kerja Twitter, ia punya bagian bernama Trending Topics. Yang Twitter lakukan adalah mengidentifikasi topik yang sedang tren dengan menganalisis jutaan dan miliaran tweet secara waktu nyata. Ia menganalisis semua tweet yang dibuat orang di seluruh dunia, mengekstrak pola dan tren, dan menghitung apa yang sedang tren.
Kenapa Komputasi Ini Mahal
Perhitungan ini sangat mahal. Ia melibatkan:
- Algoritma berbasis machine learning untuk natural language processing, pengelompokan topik, dan deteksi tren
- GPU dalam jumlah besar dan infrastruktur berat
- Memproses terabyte data, kita bicara menganalisis tweet jutaan dan miliaran orang di seluruh dunia
Apa yang Terjadi Tanpa Caching
Bayangkan jika Twitter melakukan semua perhitungan ini setiap kali pengguna pergi ke bagian trending. Jika bahkan setengah dari miliaran pengguna Twitter mencoba mengakses bagian trending, dan setiap pengguna memicu perhitungan mahal ini, server tidak sanggup menangani itu, ia akan crash dalam hitungan menit atau detik. Ada miliaran orang, dan jika setiap request memicu seluruh pipeline ML, itu mustahil dipertahankan.
Apa yang Sebenarnya Dilakukan Twitter
Untuk menghindari melakukan komputasi berat ini untuk setiap request, Twitter men-cache trending topics. Setiap beberapa menit, dan tentu kita tidak tahu algoritma eksak atau durasi eksak yang dipakai Twitter, tapi ambil estimasi kasar demi contoh ini: setiap beberapa menit, Twitter mengambil semua data ini dari berbagai region, menjalankan berbagai algoritma machine learning dan algoritma deteksi tren di tingkat yang sangat tinggi, lalu menyimpan hasilnya di in-memory key-value store seperti Redis.
Saat pengguna meminta bagian trending, alih-alih menghitungnya lagi, ia hanya mengambil data itu dari cache dan mengirimnya ke pengguna. Itulah alasan begitu Anda membuka ponsel, Anda mendapat data itu seketika, Anda tidak melihat loading time yang signifikan. Jika koneksi internet Anda umumnya cepat, seluruh interaksi UI sangat cepat.
Untuk sebuah tren berubah di region tertentu, katakanlah negara Anda sedang ada pemilu, dan pemilu adalah topik trending, itu bukan sesuatu yang berubah dalam hitungan detik atau menit. Paling tidak ia akan bertahan di bagian trending beberapa jam atau beberapa hari. Karena data ini tidak berubah secara dinamis menit-ke-menit, sangat aman untuk di-cache. TTL bisa di-set beberapa menit atau bahkan lebih lama tanpa kehilangan kesegaran yang terasa bagi pengguna.
Polanya: Mengenali Kapan Harus Cache
Setelah tiga contoh itu, Anda sekarang harusnya melihat polanya dengan jelas. Setiap kali ada situasi yang soal:
- Melakukan banyak komputasi berat: seperti algoritma ranking Google atau deteksi tren berbasis ML Twitter, Anda tidak ingin menghitung ulang untuk setiap request
- Mengirim data dalam jumlah besar ke banyak pengguna: seperti Netflix mengirim terabyte konten video secara global, Anda tidak ingin selalu melayani dari satu lokasi terpusat
Inilah dua skenario umum saat caching ikut bermain. Kenali salah satunya di diskusi desain sistem, dan caching hampir selalu bagian dari solusinya.
Tingkat Caching
Caching ada di banyak tingkat sebuah sistem komputer. Sebagai engineer backend, Anda akan menjumpai tiga tingkat paling sering:
"Berbasis perangkat lunak" tidak berarti murni perangkat lunak. Redis memakai RAM perangkat keras. Ia disebut berbasis perangkat lunak karena Anda berinteraksi dengannya lewat library atau API, sarana interaksinya perangkat lunak. Performanya tetap berasal dari perangkat keras di bawahnya (RAM).
Caching Tingkat Jaringan
Dua kasus pemakaian utama di lapisan jaringan yang ditangani engineer backend adalah caching CDN dan DNS.
4.1: CDN (Content Delivery Network)
Gagasan inti CDN adalah men-cache konten di server yang secara geografis lebih dekat ke pengguna akhir. Server apa pun yang ditempatkan dekat pengguna di "tepian" jaringan disebut Edge Node, Edge Server, atau Edge Computing.
Cara alur request CDN
Keputusan routing CDN mempertimbangkan banyak parameter:
- Lokasi geografis pengguna: temukan PoP terdekat
- Kondisi jaringan: pengguna dengan koneksi lambat bisa di-route ke PoP dengan konten resolusi lebih rendah (mis. 480p alih-alih 1080p)
- Beban server: hindari routing ke edge server yang kelebihan beban
4.2: Caching DNS
DNS (Domain Name System) menerjemahkan nama domain yang bisa dibaca manusia (seperti example.com) ke alamat IP yang dipakai browser untuk terhubung ke server. Proses resolusi ini, tanpa caching, sangat rekursif dan lambat.
Rantai Resolusi DNS (tanpa cache)
Seluruh perjalanan rekursif ini mahal. DNS menyelesaikannya dengan banyak tingkat caching:
Recursive Resolver disebut "rekursif" karena ia meng-query berbagai server secara rekursif (root -> TLD -> otoritatif) sampai menemukan jawabannya. Ia disediakan ISP Anda atau penyedia DNS publik seperti Google (8.8.8.8) atau Cloudflare (1.1.1.1).
Caching Tingkat Perangkat Keras
Hirarki Cache CPU (L1, L2, L3)
CPU tidak membaca langsung dari RAM untuk setiap operasi, itu terlalu lambat. Gantinya, ia memelihara hirarki memori lebih kecil dan lebih cepat bernama level cache:
Kenapa Larik Lebih Cepat untuk Akses Sekuensial
Konsekuensi praktis penting dari caching CPU: saat Anda mulai menelusuri larik secara sekuensial, algoritma prefetch/prediktif CPU mendeteksi pola sekuensial dan memuat seluruh larik (atau potongan besar) ke cache L1/L2 secara proaktif. Inilah kenapa for loop atas larik sangat cepat, datanya sudah di cache saat CPU membutuhkannya.
RAM vs Disk: Kenapa RAM Lebih Cepat (Fisikanya)
Ini alasan fundamental kenapa database dalam memori seperti Redis jauh lebih cepat daripada database berbasis disk seperti PostgreSQL atau MySQL. Memahami perbedaan perangkat keras sebenarnya penting, ini bukan sihir, ini fisika dan rekayasa.
Cara Kerja Penyimpanan Hard Disk
Di hard disk drive (HDD) tradisional, ada semacam kepala mekanis yang berputar mengelilingi disk. Saat Anda ingin membaca data, disk berputar, kepala bergerak ke track yang benar, dan ia secara fisik menemukan datanya. Itu operasi mekanis. Pikirkan, lengan fisik sungguhan harus bergerak ke satu lokasi di piringan yang berputar. Gerakan mekanis ini memakan waktu, milidetik, yang dalam istilah komputasi adalah keabadian.
Cara Kerja RAM
Random Access Memory pada dasarnya berbeda. Ia punya sekumpulan kapasitor dan transistor, dan lewat pemakaian sinyal listrik yang dikombinasikan dengan akses langsung berbasis alamat, ia bisa mengakses lokasi mana pun di memori dengan satu sinyal listrik. Tidak ada gerakan fisik, tidak ada seeking, tidak ada spinning. Data diakses dengan mengirim sinyal listrik ke alamat memori spesifik, dan itu terjadi mendekati kecepatan listrik itu sendiri.
Inilah juga kenapa disebut Random Access Memory, ia tidak peduli dari arah mana Anda mencoba mengakses data. Kecepatan dan waktunya hampir konstan di mana pun data berada di memori. Entah Anda mengakses alamat 0x0001 atau 0xFFFF, waktu pengambilannya pada dasarnya sama. Sifat ini disebut waktu akses O(1) dalam istilah struktur data.
Bandingkan dengan hard disk: mengakses data secara sekuensial (dari alamat 0 ke 100) cepat karena kepala tidak harus banyak bergerak. Tapi mengakses data secara acak (melompat dari alamat 0 ke 9000 ke 200 ke 7000) sangat lambat karena kepala harus mencari lokasi berbeda secara fisik tiap kali. Itulah kenapa HDD menyukai pola akses sekuensial.
| Sifat | RAM (Penyimpanan Primer) | HDD (Penyimpanan Sekunder) | SSD (Penyimpanan Sekunder) |
|---|---|---|---|
| Mekanisme akses | Sinyal listrik -> alamat memori | Kepala mekanis mencari piringan berputar | Sel memori flash, listrik |
| Waktu akses | ±60-100 nanodetik | ±5-10 milidetik | ±50-150 mikrodetik |
| Kecepatan relatif | ±100.000x lebih cepat dari HDD | Baseline | ±100x lebih cepat dari HDD |
| Akses acak | O(1), konstan di mana pun | Lambat, butuh seek mekanis | Bagus, tanpa bagian mekanis |
| Volatilitas | Volatile, data hilang saat mati | Persisten, bertahan saat mati | Persisten, bertahan saat mati |
| Kapasitas (server khas) | 64GB, 512GB | Beberapa TB | Beberapa TB |
| Biaya per GB | ±$5-10/GB | ±$0.02-0.05/GB | ±$0.10-0.20/GB |
Kompromi Fundamental
Soal Random Access Memory, kita menukar non-volatilitas dan kapasitas demi kecepatan. Itu komprominya dinyatakan polos. RAM sangat cepat tapi:
- Ia volatile. Kapan pun Anda mematikan daya, apa pun data yang tersimpan di RAM, ia hilang. Ia membersihkan diri. Mulai segar kapan pun Anda menyalakan komputer. Ini karena cara kerja kapasitor, mereka butuh pasokan listrik konstan untuk memegang state-nya. Potong daya, state-nya menghilang.
- Kapasitasnya terbatas. Meski kecepatan ada di tangan kita dengan RAM, kita tidak memilikinya berlimpah. Biaya manufaktur RAM di skala berarti server punya RAM jauh lebih sedikit daripada penyimpanan disk.
Inilah kenapa Anda tidak bisa sepenuhnya mengganti hard disk atau penyimpanan berbasis disk tradisional dengan RAM. Mereka punya peran sendiri, cepat soal akses dan pengambilan data, tapi bukan pengganti penyimpanan sekunder. Menyimpan data di penyimpanan sekunder itu permanen, tidak volatile. Tidak peduli apakah program Anda mengaksesnya atau tidak, apakah komputer Anda menyala atau mati, data tetap ada di sana karena ia secara fisik menuliskan data ke disk.
Penyimpanan primer (RAM): Akses data sangat cepat, kapasitas terbatas, volatile (data hilang saat mati). Dipakai untuk data yang perlu diproses sekarang atau diambil seketika. Penyimpanan sekunder (HDD/SSD): Akses data lebih lambat, kapasitas berlimpah, non-volatile (data bertahan). Dipakai untuk penyimpanan permanen semua data Anda.
Cara Redis Menjembatani Kedua Dunia
Teknologi seperti Redis dan Memcached memakai Random Access Memory ini (memori primer / memori utama) untuk menyimpan datanya, itulah kenapa operasi akses data dari database ini sangat cepat. Tapi bagaimana dengan persistensi? Bagaimana dengan fakta RAM kehilangan data saat mati?
Di balik layar, untuk persistensi, teknologi ini juga memakai penyimpanan sekunder. Dengan semacam mekanisme, saat program mulai, ia mengambil data dari penyimpanan sekunder dan memuatnya ke memori utama lagi, jadi Anda punya persistensi data. Tapi saat Anda benar-benar mengambil atau memodifikasi data, itu terjadi dengan memori primer. Database dalam memori bertanggung jawab mengimplementasikan lapisan persistensi ini, entah snapshot RDB Redis atau log AOF (Append-Only File)-nya.
Database NoSQL Key-Value Dalam Memori
Kembali ke konteks pengembangan backend, teknologi seperti Redis, Memcached, dan jika kita bicara teknologi Cloud maka AWS ElastiCache: inilah yang ikut bermain. Mereka menyediakan semacam penyimpanan, dan penyimpanan itu berbasis memori primer (RAM). Itulah alasan operasi akses data dari database ini sangat cepat.
Kita menyebut teknologi ini database NoSQL key-value dalam memori. Nama itu punya empat bagian, dan masing-masing memberi tahu Anda satu hal penting:
Dalam Memori
Dibanding database tradisional seperti PostgreSQL atau MySQL, ini tidak disimpan di disk. Penyimpanannya berbasis RAM (penyimpanan primer). Itulah alasan operasi akses data sangat cepat, kita baru saja memahami di bagian perangkat keras persis kenapa RAM lebih cepat berlipat ganda dari akses berbasis disk. Redis membaca dan menulis ke RAM, bukan disk.
Key-Value
Dibanding database relasional tradisional yang punya skema sangat ketat, Anda harus membuat tabel, membuat baris, mendefinisikan kolom dengan tipe, dll., di sini struktur datanya sangat sederhana. Anda punya key dan value. Anda punya satu key tertentu, dan untuk key itu Anda bisa menyimpan apa pun, bisa larik, objek JSON, string, angka, hash, set. Teknologi berbeda menawarkan tipe data berbeda, tapi antarmukanya selalu: beri aku key, kuberi nilainya.
NoSQL
Mereka tidak menegakkan keketatan database SQL tradisional. Tanpa skema, tanpa join, tanpa query rumit. API-nya sengaja sederhana. Di Redis, Anda intinya punya SET key value dan GET key sebagai operasi utama. Tidak rumit seperti query SQL dengan agregasi, GROUP BY, dll., aksesnya cukup langsung.
Database
Meski "cuma" key-value store, ini database kelas penuh dengan fitur seperti kedaluwarsa berbasis TTL, opsi persistensi, pesan pub/sub, skrip Lua (Redis), clustering dan replikasi. Label "database" memang layak, mereka mengelola data dengan andal, bukan sekadar cache sembarang.
Kenapa Kesederhanaan Key-Value adalah Fitur, Bukan Keterbatasan
Anda mungkin bertanya: kenapa memakai database tanpa query rumit? Jawabannya: semua kompleksitas yang tidak Anda miliki adalah performa yang Anda dapatkan kembali. Saat Redis menerima perintah GET, ia benar-benar hanya mencari hash table di memori. Tanpa parsing query, tanpa perencanaan query, tanpa I/O disk, tanpa penelusuran index. Itu pencarian memori O(1), itulah kenapa Redis bisa melayani jutaan operasi per detik.
Inilah yang akan Anda tangani sebagai engineer backend: Anda ambil library kompatibel apa pun yang tersedia di bahasa pemrograman Anda (Node.js punya node-redis atau ioredis, Go punya go-redis, Python punya redis-py), dan tergantung itu Anda tinggal pakai library-nya. Anda beri key, beri value, menyimpannya. Dan saat ingin mengambil, beri key dan dapat value. Cukup langsung, tanpa kerumitan seperti query SQL dan agregasi. Tapi semua keakraban teknis dengan cara kerja teknologi di balik layar, apa komponen utamanya, membantu Anda memahami keseluruhannya dan membuat keputusan lebih baik.
Cara Redis Menangani Persistensi
Redis memakai dua mekanisme utama untuk memastikan data tidak hilang saat proses restart:
- RDB (Redis Database) Snapshot: Pada interval terkonfigurasi (mis. setiap 5 menit, atau saat N tulisan terjadi), Redis fork proses dan menulis seluruh dataset dalam memori ke file biner
.rdbdi disk. Saat startup, Redis memuat file ini kembali ke memori. Restart cepat, tapi Anda bisa kehilangan sampai N menit data. - AOF (Append-Only File): Setiap operasi tulis dicatat ke file append-only di disk. Saat restart, Redis memutar ulang semua operasi ini untuk membangun ulang state dalam memori. Kehilangan data hampir nol, tapi restart lebih lambat dan file tumbuh lebih besar seiring waktu (Redis memadatkannya berkala lewat proses rewrite latar).
- Keduanya bersama: Redis merekomendasikan memakai RDB + AOF di produksi untuk keseimbangan terbaik antara performa dan daya tahan.
Wawasan kuncinya: data selalu dibaca dari dan ditulis ke RAM selama operasi normal. Disk hanya terlibat untuk persistensi (menyimpan state untuk pemulihan). Jalur panas, jalur yang diambil setiap request pengguna, tidak pernah menyentuh disk.
Strategi Caching
Ada dua strategi caching utama yang akan Anda temui di pengembangan backend sehari-hari. Keduanya menjawab pertanyaan berbeda: kapan Anda mengisi cache? dan kapan Anda memperbaruinya?
Lazy Caching (Cache-Aside)
Cache hanya diisi saat data pertama kali diminta. Pengisian awal proaktif tidak dilakukan.
Write-Through Caching
Setiap tulis ke database sekaligus ditulis ke cache. Cache selalu segar.
Strategi 1: Lazy Caching (Cache-Aside)
Karakteristik Lazy Caching:
- Cache hanya diisi saat data benar-benar diminta, tanpa pengisian awal yang terbuang
- Request pertama untuk data apa pun selalu menghasilkan cache miss (latensi sedikit lebih tinggi untuk pengguna pertama)
- Risiko data basi, jika DB di bawahnya berubah, nilai ter-cache bisa usang sampai TTL kedaluwarsa atau invalidasi manual
- Sederhana diimplementasikan dan sangat umum dalam praktik
Strategi 2: Write-Through Caching
Setiap kali operasi tulis (POST, PUT, PATCH) mengubah data di database, perubahan yang sama sekaligus diterapkan ke cache dalam alur eksekusi panggilan API yang sama.
Cache selalu segar. Anda tidak pernah menyajikan data basi karena cache diperbarui di waktu yang sama persis dengan database.
Setiap operasi tulis membawa overhead tambahan: Anda harus memperbarui database dan cache secara atomik (atau hampir atomik). Ini menambah latensi operasi tulis. Jika operasi tulis sangat sering, ini bisa menjadi bottleneck.
Kapan memakai yang mana?
| Skenario | Strategi |
|---|---|
| Read-heavy, tulis jarang (halaman produk, profil) | Lazy caching + TTL |
| Butuh cache selalu segar (data finansial, inventaris) | Write-through |
| Pola akses tidak diketahui, peluncuran bertahap | Lazy caching (mulai lebih aman) |
| Beban kerja tulis berat (logging, event stream) | Hindari write-through |
Kebijakan Eviction
Hal lain yang harus kita sadari saat bekerja dengan cache dalam memori seperti Redis adalah kebijakan eviction. Apa artinya? Mari pahami masalahnya dulu.
Kenapa Eviction Perlu
Saat Anda punya cache, dan seperti sudah kita tahu, cache dalam memori seperti Redis memakai penyimpanan primer (RAM), yang kapasitasnya terbatas dibanding penyimpanan sekunder, sudah jelas bahwa pada satu titik Anda akan kehabisan memori. Entah Anda menjalankan Redis di server sendiri dan RAM penuh, atau memakai layanan terkelola seperti AWS ElastiCache yang punya batas penyimpanan, pada satu titik Anda akan kena plafon.
Pada titik itu, Anda harus memutuskan: Anda ingin menyimpan data baru di cache, tapi tidak ada ruang. Anda harus menghapus sesuatu yang lama untuk memberi ruang bagi yang baru. Dan tentu, seperti sudah dibahas dari bagian awal topik ini, cache hanyalah subset dari data, data yang sering diakses disimpan di lokasi berbeda yang lebih cepat. Kata kuncinya: subset dari penyimpanan primer. Kita tidak bisa menyimpan semua penyimpanan primer di cache. Jadi kita harus memutuskan apa yang tinggal dan apa yang pergi.
Potongan data ter-cache mana yang paling tidak berharga untuk disimpan? Evict itu, beri ruang bagi data baru yang prioritasnya lebih tinggi. Kebijakan eviction berbeda menjawab pertanyaan ini secara berbeda.
- NO EVICTION. Tidak ada kebijakan eviction yang dikonfigurasi. Ini default jika Anda belum mengonfigurasi kebijakan eviction apa pun. Apa yang terjadi saat cache penuh dan Anda mencoba menyisipkan data baru? Anda cuma dapat error: memori penuh, operasi ditolak. Ini tidak masuk akal untuk kasus pemakaian cache, tapi ia ada sebagai konfigurasi karena ada situasi tempat Anda secara eksplisit ingin mengendalikan ukuran cache dan jangan pernah diam-diam membuang data. Untuk kasus caching sungguhan, Anda harus selalu mengonfigurasi salah satu kebijakan di bawah.
- LRU Least Recently Used. Algoritmanya memeriksa data mana yang paling jarang diakses baru-baru ini. Ia melacak kapan terakhir kali sebuah key tertentu diakses. Contoh berjalan dari kuliah: Anggap kita punya 4 key di cache, Key 1, Key 2, Key 3, Key 4, dan memori sekarang penuh. Database melacak kapan tiap key terakhir diakses: Key 1, diakses hari ini Key 2, diakses hari ini Key 3, diakses hari ini Key 4, diakses kemarin Sekarang Key 5 ingin masuk cache. Dengan kebijakan eviction LRU, Redis memeriksa data mana yang paling lama diakses. Karena Key 4 diakses kemarin dan semua yang lain hari ini, ia memilih Key 4: "kamu keluar, Key 5 masuk." Itulah eviction Least Recently Used. Kapan memakai: LRU kebijakan eviction yang paling umum dipakai. Ia bekerja baik untuk beban kerja tempat data yang baru diakses kemungkinan besar diakses lagi segera, yang berlaku untuk kebanyakan aplikasi dunia nyata (temporal locality).
- LFU Least Frequently Used. Alih-alih melacak kapan sebuah key terakhir diakses, LFU melacak berapa kali total setiap key diakses. Key dengan jumlah akses terendah di-evict. Contoh berjalan dari kuliah: Lupakan waktu, anggap kita punya 4 key dan Key 5 ingin masuk. Tiap key punya penghitung frekuensi akses: Key 1, diakses 5 kali sejauh ini Key 2, diakses 10 kali sejauh ini Key 3, diakses 6 kali sejauh ini Key 4, diakses 23 kali sejauh ini Key 5 tiba dan butuh ruang. LFU memeriksa key mana yang paling jarang dipakai, yang frekuensinya terendah. Key 1 baru diakses 5 kali, paling sedikit. Key lain diakses lebih sering. Jadi ia memilih Key 1: "kamu keluar, Key 5 masuk." Kapan memakai: LFU bekerja lebih baik daripada LRU saat aplikasi Anda punya set "hot" items yang stabil dan selalu populer (seperti katalog produk tempat 100 produk teratas menerima 80% lalu lintas). LRU bisa meng-evict item panas yang kebetulan tidak diakses semenit terakhir, sedangkan LFU mempertahankannya karena frekuensi jangka panjangnya tinggi.>
- BERBASIS TTL
Volatile-TTL (Eviction Berbasis Time-to-Live). Di Redis Anda bisa mengonfigurasi TTL, time-to-live, untuk key berbeda secara individual. Saat cache penuh dan perlu evict sesuatu, dengan kebijakan ini ia memeriksa key mana yang punya TTL tersisa terendah: yaitu, key mana yang toh paling cepat kedaluwarsa.
Contoh berjalan: Skenario sama, 4 key, Key 5 mau masuk, cache penuh. Tiap key punya TTL:
Key 1, kedaluwarsa dalam 3 jam
Key 2, kedaluwarsa dalam 45 menit
Key 3, kedaluwarsa dalam 2 jam
Key 4, kedaluwarsa dalam 10 menit (paling cepat kedaluwarsa)
Key 5 tiba. Kebijakannya memilih Key 4, ia toh akan kedaluwarsa dalam 10 menit, jadi sebaiknya evict sekarang dan beri ruang untuk Key 5. Logikanya: "key ini sebentar lagi hilang juga, jadi lepaskan sekarang."
Catatan: TTL juga dipakai terpisah dari eviction untuk sekadar mengeluarkan data basi secara otomatis. Anda set key dengan
SETEX weather_delhi "25 degC" 3600dan setelah 3600 detik (1 jam), Redis otomatis menghapusnya. Anda tidak perlu membersihkannya manual. Ini salah satu fitur Redis paling berguna untuk caching respons API eksternal.nses.