Ketika cache berskala ke arah yang salah
Empat berkas kecil berada di folder cache layanan ini. Yang terbesar berukuran 35 byte. Bersama-sama, berkas-berkas itu menyimpan tiga nomor penghitung, dan dibaca pada setiap permintaan penghitung.
Berkas-berkas itu ada agar jalur penghitungan tidak perlu mengajukan empat pertanyaan kepada basis data yang hampir selalu dijawab dengan “tidak”. Apakah penghitung ini mengecualikan kunjungan pemiliknya sendiri? Melacak klik keluar? Melacak jalur di dalam situs? Memuat ulang dirinya sendiri? Untuk lebih dari 99% penghitung, setiap jawabannya adalah tidak, dan berkas yang memuat segelintir nomor yang jawabannya ya lebih murah untuk dirujuk daripada empat kueri berindeks.
Memang lebih murah. Tetapi ini juga jenis murah yang bisa berbalik.
Apa yang diukur
Pertanyaan yang sama — “apakah penghitung ini ada di daftar?” — diajukan dengan dua cara, pada enam ukuran daftar. Cara berkas: membacanya, mendekode JSON, mencari nomornya. Cara basis data: satu prepared statement terhadap kolom berindeks. Masing-masing dua ribu pengulangan, lima putaran, diambil mediannya.
Pada ukuran saat ini, berkas menang delapan kali lipat: 0,0202 milidetik berbanding 0,1630. Pada seribu nomor keduanya setara. Pada sepuluh ribu, berkas memakan biaya dua belas kali lebih besar, dan pada seratus ribu 135 kali lebih besar, karena saat itu berkasnya sudah berukuran 578 kilobyte yang harus dibaca dan diurai pada setiap tayangan.
Garis basis data tidak bergerak. 0,16 milidetik pada dua baris dan 0,16 milidetik pada seratus ribu: itulah gunanya indeks, dan mudah terlupa betapa banyak kerja yang tersembunyi di balik garis yang tampak begitu membosankan itu.
Bagian yang tidak nyaman
Titik silangnya berada di antara 100 dan 1.000 nomor. Layanan ini memiliki 2.218 penghitung yang aktif dalam tiga puluh hari terakhir.
Jadi jika fitur pengecualian itu sukses — jika setiap orang yang memiliki penghitung mengaktifkan “jangan hitung kunjungan saya sendiri” — berkas itu akan memuat 2.218 nomor, berbobot 11 kilobyte, dan memakan 0,43 milidetik per tayangan alih-alih 0,02. Dengan 18.423 tayangan kemarin, itu delapan detik kerja per hari untuk menghindari kueri yang akan memakan waktu tiga detik.
Optimasi ini paling cepat ketika fiturnya paling jarang digunakan. Optimasi ini tidak menurun secara bertahap seiring beban, seperti kueri yang lambat. Optimasi ini menurun seiring adopsi, yaitu satu-satunya sumbu yang tidak diamati siapa pun, karena adopsi yang naik seharusnya merupakan kabar baik.
Mengapa berkas itu masih ada
Karena berkas itu benar untuk hari ini, dan “benar untuk hari ini” boleh menjadi alasan untuk sesuatu, asalkan seseorang mencatat kapan hal itu berhenti benar.
Tiga nomor dalam tiga berkas. Delapan kali lebih murah daripada alternatifnya, pada mesin yang jalur penghitungannya adalah satu-satunya hal yang harus cepat. Menggantinya sekarang dengan kueri yang dikalahkannya berarti sistem yang lebih buruk yang dibenarkan oleh sebuah hipotesis.
Yang dibutuhkan adalah pemicu peringatan, bukan penulisan ulang. Berkas itu toh ditulis dari basis data, oleh kode yang mengubah sebuah pengaturan — di situlah tempat yang wajar untuk menyadari bahwa daftar telah tumbuh melampaui beberapa ratus entri dan menyampaikannya. Cache dengan batas atas yang terdokumentasi adalah sebuah keputusan. Cache tanpa batas itu adalah taruhan yang tidak pernah disetujui siapa pun.
Bentuk umumnya
Ini bukan argumen menentang cache di dalam berkas. Ini argumen untuk mengetahui ke arah mana sebuah cache berskala.
Sebagian besar cache menjadi lebih baik di bawah beban: lebih banyak permintaan, lebih banyak hit, rasio yang lebih baik. Cache ini jenis yang lain. Biayanya per permintaan bergantung pada seberapa banyak data yang disimpannya, dan apa yang disimpannya tumbuh seiring hal yang justru ingin didorong oleh layanan ini. Setiap pembacaan membayar untuk setiap entri, termasuk 2.215 entri yang tidak ada hubungannya dengan pengunjung yang sedang dihitung saat ini.
Pertanyaan yang perlu diajukan pada setiap tabel pencarian yang disimpan di memori atau di berkas bukanlah “seberapa cepat ia”, melainkan “apa yang membuatnya tumbuh, dan apa yang terjadi ketika hal itu berjalan baik”. Jika jawabannya “ia menjadi lebih lambat”, batas ukurannya harus ada di dalam kode, di samping bagian yang menulis berkas itu, sejak hari berkas itu dibuat.