Tingkat cache hit dan kualitas kebijakan cache
Tingkat keberhasilan hanyalah indikator hasil. Yang benar-benar menentukan biaya sistem adalah mode kegagalan, tekanan balik, dan radius propagasi kesalahan.
Ketika banyak tim berbicara tentang caching, hal pertama yang mereka katakan adalah hit rate.
Tingkat keberhasilan 95% terdengar bagus; 98% tampaknya dioptimalkan; 99% bahkan memberikan ilusi kepada orang-orang bahwa sistem tersebut telah “dijinakkan”.
Namun ketika terjadi kesalahan saat online, semua orang sering kali melihat serangkaian masalah lain saat melakukan peninjauan: database ditembus setelah kumpulan kunci tertentu kedaluwarsa pada saat yang sama, pengguna masih melihat data lama dalam waktu satu jam setelah harga diubah, node cache bergetar, dan kueri yang paling mahal semuanya langsung masuk ke database utama.
Penilaian saya sederhana: **Tujuan dari strategi cache adalah untuk mengendalikan biaya “kesalahan”. ** Tingkat hit yang tinggi hanya berarti banyak permintaan dibaca ke dalam cache; ini tidak berarti bahwa desain kegagalan sudah benar, tidak berarti bahwa biaya pengembalian ke sumbernya dapat dikendalikan, dan tidak berarti bahwa kesalahan akan terbatas pada kisaran kecil.
Jika cache meningkatkan tingkat hit dari 92% menjadi 99%, namun mengakibatkan lebih sulit untuk membatalkan validasi, lebih sulit untuk menemukan data kotor, dan lebih cenderung membentuk badai kembali ke asal selama jitter, kemungkinan besar hal tersebut bukan optimasi, namun hanya memindahkan kompleksitas dari database ke sudut lain.
Pertanyaannya bukan “berapa banyak pukulan”, tetapi “di mana memukul ketika meleset”
Indikator hit rate memiliki kelemahan alami: indikator ini meratakan distribusi panas dan dingin.
Satu antarmuka menerima satu juta permintaan setiap hari, 990.000 di antaranya membaca detail produk populer, dan 10.000 sisanya membaca produk jangka panjang. Cache data populer dan hit rate akan segera menjadi sangat baik. Namun jika 10.000 kesalahan jangka panjang tersebut terjadi pada kueri paling lambat dan paling mahal yang juga melibatkan penggabungan tabel, tekanan database mungkin tidak kurang dari yang dibayangkan.
Dengan kata lain, hit rate dihitung sebagai “berapa kali”, namun biaya sistem sering kali diselesaikan sebagai “harga”. **
Hal ini juga menunjukkan bahwa beberapa tim dengan jelas melihat indikator cache yang indah, namun CPU database masih tidak dapat melambat: cache memblokir permintaan yang murah, dan kesalahan yang sangat mahal masih berjalan dengan telanjang.
Saat menilai strategi caching, saya lebih suka melihat tiga hal terlebih dahulu:
- Melewatkan bagian permintaan yang paling mahal;
- Apakah kesalahan akan terjadi secara terkonsentrasi dan tidak merata;
- Apakah stress akan diteruskan ke hilir setelah miss?
Ketiga pertanyaan ini lebih dekat dengan biaya sebenarnya dibandingkan “apakah tingkat keberhasilan keseluruhan naik 2 poin lagi?”
Yang benar-benar menentukan kualitas cache biasanya adalah metode kegagalannya.
Banyak kecelakaan cache pada dasarnya adalah “desain kegagalan yang terlalu kasar”.
Pendekatan yang paling umum adalah dengan menetapkan TTL. Implementasinya sederhana dan indikatornya mudah untuk ditingkatkan, karena selama TTLnya cukup panjang, hit ratenya biasanya tidak terlalu buruk. Namun ada dua masalah umum pada skema TTL.
Pertama, ada waktu untuk memutuskan kapan data akan habis masa berlakunya, dibandingkan perubahan bisnis. **
Harga telah berubah, inventaris telah berubah, izin telah berubah, namun cache masih hidup. Tentu saja TTL dapat diperpendek, namun begitu TTL diperpendek, frekuensi kembali ke sumber akan meningkat lagi. Banyak tim yang bolak-balik antara “data lama terlalu tua” dan “database terlalu sibuk”.
Kedua, mudahnya menyebabkan kegagalan sinkronisasi. **
Jika sekumpulan hot key ditulis pada waktu yang sama dan menggunakan TTL yang sama, kemungkinan besar masa berlakunya akan habis bersamaan pada waktu yang sama. Biasanya, tingkat hit baik-baik saja, tetapi segera setelah mencapai titik kedaluwarsa, akan ada puncak kembali ke sumber secara instan. Ini mungkin hanya berupa gangguan selama lima menit di dasbor, namun ini merupakan pukulan nyata terhadap database dan layanan hilir.
Oleh karena itu, hal terpenting dalam desain cache adalah apakah mekanisme kegagalan selaras dengan perubahan bisnis.
Modifikasi umum meliputi:
- Gunakan kegagalan yang didorong oleh peristiwa, bukan hanya mengandalkan TTL;
- Tambahkan jitter acak ke TTL untuk mencegah kunci hotspot kedaluwarsa secara bersamaan;
- Masukkan nomor versi atau stempel waktu ke dalam kunci untuk secara eksplisit mengalihkan pembuatan data;
- Izinkan nilai lama dikembalikan untuk jangka waktu singkat, namun disegarkan secara asinkron di latar belakang alih-alih membuat semua permintaan kembali ke asal secara bersamaan.
Intinya di sini adalah Anda perlu memutuskan kapan menerima data lama, kapan harus segera konsisten, dan kapan Anda lebih suka mengembalikan hasil downgrade daripada meledakkan database utama. ** Ini adalah strategi caching, dan hit rate hanyalah bayangannya saja.
Memperluas TTL sering kali hanya memperburuk masalah.
Saya telah melihat banyak “optimasi cache” yang dilakukan seperti ini: database online berada di bawah tekanan, sehingga TTL diubah dari 5 menit menjadi 30 menit, dan kemudian menjadi 1 jam. Hasilnya, hit rate meningkat dan kurva database menjadi sedikit datar, dan tim mengumumkan bahwa pengoptimalan telah selesai.
Hal yang paling berbahaya dari pendekatan ini adalah terlalu mudah untuk terlihat efektif dalam jangka pendek.
Karena kebanyakan sistem indikator lebih baik dalam mencatat “berapa banyak query yang disimpan” dan tidak pandai dalam mencatat “berapa banyak data yang salah yang disimpan”. Ketika harga lama, konfigurasi lama, dan izin lama dibaca oleh lebih banyak pengguna, kerugian sering kali tidak langsung terlihat di panel cache, namun nantinya akan muncul dalam keluhan, kompensasi, verifikasi manual, dan tinjauan kecelakaan.
Khusus untuk jenis data berikut, memperluas TTL secara kasar seringkali merupakan ide yang buruk:
- Data yang akan mempengaruhi jumlah penyelesaian;
- Data yang mempengaruhi izin dan visibilitas;
- Data yang tidak sering diperbarui, namun harus dikumpulkan secepat mungkin setelah diperbarui.
Untuk jenis data ini, jika hit rate tertinggi diperoleh dengan “pengenalan perubahan yang tertunda”, maka akurasinya terlalu berlebihan. **
Bagian tersulit dari caching adalah membatasi kesalahan
Situasi yang umum adalah menganggap caching sebagai “lapisan tambahan di depan database”. Pemahaman ini tidak salah, namun terlalu optimis.
Caching dalam sistem nyata adalah permukaan tekanan yang memperkuat kelemahan desain. Jika kunci dirancang terlalu tebal, cakupan kegagalannya akan terlalu besar; jika kunci dirancang terlalu tipis, penggunaan memori dan kompleksitas pemeliharaan akan meningkat; kumpulan data ditempatkan di lapisan cache, dan mudah untuk mengulangi penghitungan saat kembali ke sumbernya; cache lokal dan cache terdistribusi ditumpuk bersama-sama, dan akan ada lapisan masalah konsistensi tambahan.
Jadi saya akan membagi solusi caching menjadi dua pertanyaan untuk ditinjau:
- Apakah kamu biasanya bahagia atau tidak?
- Jika terjadi kesalahan, apakah hal tersebut akan menyeret bagian lain dari sistem?
Pertanyaan terakhir biasanya lebih penting.
Implementasi cache yang lebih andal sering kali secara eksplisit menangani hal-hal berikut:
v, ok := cache.Get(key)
if ok && !v.SoftExpired() {
return v.Data
}
return singleflight.Do(key, func() any {
fresh := db.Load(id)
cache.Set(key, fresh, ttlWithJitter())
return fresh
})
Yang sangat berharga di sini adalah dua kendala:
- Ketika kunci yang sama dikembalikan ke asal, hanya satu permintaan yang diperbolehkan untuk benar-benar masuk ke database;
- Kedaluwarsa memberi sistem jendela penyegaran yang dapat dikontrol.
Jenis desain ini belum tentu mencapai tingkat serangan terbaik, namun dapat secara signifikan mengurangi badai balik dan amplifikasi seketika. Tanpa jitter, sistem lebih seperti “melambat” daripada “runtuh”.
Kesalahpahaman umum: memperlakukan tingkat cache hit sebagai KPI tim
Ketika persentase pencapaian menjadi KPI, mudah bagi tim untuk bekerja ke arah yang salah.
Karena cara termudah untuk meningkatkan hit rate adalah dengan meningkatkan hasil statistik:
- Regangkan TTL;
- Masukkan lebih banyak data yang tidak boleh di-cache;
- Gunakan tombol berbutir kasar untuk menggabungkan berbagai adegan menjadi satu;
- Memisahkan antarmuka agar ramah cache membuat semantik bisnis menjadi lebih buruk.
Tindakan ini mungkin membuat grafik terlihat lebih baik, namun akan memunculkan masalah lain: jendela data kotor akan lebih panjang, kegagalan akan lebih sulit, pemecahan masalah akan lebih sulit, memori akan lebih mahal, dan batasan bisnis akan kabur.
Pendekatan yang lebih sehat adalah dengan melihat cache bersama dengan metrik berikut:
- Miss P95/P99 membutuhkan waktu untuk kembali ke sumbernya;
- Jumlah kunci hotspot kembali ke sumber secara bersamaan;
- Tingkat kesalahan dan puncak basis data setelah pembatalan cache;
- Waktu yang diperlukan data untuk menyatu ke nilai baru setelah diperbarui;
- Berapa banyak jalur kode tambahan dan tindakan operasional yang diperkenalkan untuk memelihara cache.
Hanya ketika biaya-biaya ini digabungkan barulah tingkat keberhasilan mempunyai kekuatan untuk menjelaskan. Melihatnya sendiri, terlalu mudah untuk dibodohi.
Contoh balasan: Dalam beberapa skenario, hit rate harus setinggi mungkin
Anda tidak bisa mengatakannya sampai mati begitu saja.
Jika data secara alami stabil, atau hanya sumber daya yang tidak dapat diubah, seperti file statis, konfigurasi berversi, konten distribusi CDN, dan tabel kamus yang jarang berubah, maka hit rate memang merupakan tujuan yang sangat penting. Karena dalam skenario seperti ini, “yang lebih tua” bukanlah masalah yang serius, kegagalannya relatif sederhana, dan jalur kembali ke sumbernya biasanya jelas dan dapat dikontrol.
Ada juga beberapa sistem berbasis alat internal yang jumlah datanya tidak besar, jarang menulis, dan biaya bisnis untuk pembacaan kotor sesekali juga sangat rendah. Dalam hal ini, solusi TTL sederhana mungkin tepat. Di permukaannya terlihat mewah, namun kenyataannya mendekati cukup murah.
Jadi artikel ini menentang pengambilan hit rate di luar konteks dan menggunakannya sendiri sebagai bukti apakah cache berhasil.
Ringkasan
Untuk menilai apakah solusi caching dapat diandalkan, pertama-tama saya akan bertanya: **Apa yang akan terjadi jika kesalahan paling mahal dalam sistem ini terjadi? **
Jika jawabannya “hanya sedikit lebih lambat, sistem masih bisa stabil”, maka kemungkinan besar cache tersebut dirancang.
Jika jawabannya adalah “hit rate biasanya sangat tinggi, tetapi jika gagal, itu akan menembus database utama dan menurunkan keakuratannya”, maka itu hanyalah bahaya tersembunyi yang tampaknya bekerja keras di waktu-waktu biasa.
Caching bukan sekadar tentang “mendekatkan data”. Yang benar-benar diuji adalah bagaimana menghadapi perubahan, kegagalan, dan biaya. Tingkat keberhasilan yang tinggi berarti Anda telah menyelesaikan paruh pertama kalimat dengan paling baik; paruh kedua kalimatlah yang menentukan apakah strategi tersebut layak dilakukan.
What to read next
Want more posts about Caching?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #Performance Optimization?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home