Setiap kali membangun aplikasi di atas Cloudflare Workers, ada satu pertanyaan yang menurut saya sering dilewatkan begitu saja, data ini sebaiknya disimpan di mana. Cloudflare menyediakan beberapa jenis storage sekaligus, Workers KV, D1, dan Durable Objects, dan ketiganya sama sama mudah dipasang lewat binding di wrangler.toml. Karena sama sama gampang dipasang, banyak yang memilih salah satunya asal tersedia dan berfungsi, tanpa mengecek dulu apakah pola pemakaiannya memang cocok. Saya sendiri baru benar benar menyadari bedanya setelah kena akibatnya langsung.
Workers KV, untuk data yang jarang berubah
KV adalah key-value store yang paling sering jadi pilihan pertama karena paling sederhana. Tapi kesederhanaan itu menyimpan satu detail penting, setiap kali menulis satu nilai, Cloudflare menyebarkan data itu ke jaringan edge-nya di seluruh dunia, supaya nanti bisa dibaca cepat dari lokasi mana pun. Proses penyebaran ini butuh waktu, bisa sampai 60 detik sebelum perubahan terlihat di lokasi lain, karena itu KV disebut eventually consistent, bukan langsung konsisten begitu ditulis.
Konsekuensinya, menulis di KV itu mahal secara arsitektur karena harus disebar ke banyak tempat, sementara membaca jauh lebih murah karena tinggal diambil dari cache terdekat. Itu tercermin langsung di kuota gratisnya, cuma 1.000 tulisan per hari, tapi bacanya sampai 100.000 per hari. Cloudflare sendiri menyebutkan KV cocok untuk data konfigurasi, metadata routing, atau personalisasi semacam A/B testing, jenis data yang jarang berubah tapi harus dibaca berkali kali dari seluruh dunia.
D1, untuk data terstruktur yang sering berubah
D1 adalah database SQL milik Cloudflare, dan cara kerjanya berbeda jauh dari KV. Data D1 tersimpan di satu tempat, tidak perlu disebar ke seluruh dunia, sehingga kuota tulisnya jauh lebih longgar, 100.000 baris per hari untuk plan gratis, dengan 5 juta baris baca per hari. D1 pas dipakai untuk data yang memang sering berubah dan berbentuk terstruktur, seperti log aktivitas, riwayat transaksi, atau profil pengguna.
Durable Objects, untuk satu sumber kebenaran yang konsisten real time
Ada juga Durable Objects, yang saya taruh sebagai opsi ketiga untuk kebutuhan yang lebih spesifik lagi. Setiap Durable Object punya storage sendiri yang strongly consistent, cocok untuk sesi kolaboratif, koordinasi real time antar klien, atau penghitung yang harus tetap benar walau diakses bersamaan dari banyak tempat. Bentuknya lebih berat dipasang dibanding KV atau D1, jadi bukan pilihan default untuk sekadar menyimpan log atau status sederhana.
Contoh kasus, kuota Workers KV yang nyaris habis
Pemahaman soal beda ketiganya ini justru saya dapatkan dengan cara yang tidak enak. Pagi itu saya buka email dari Cloudflare, akun saya sudah memakai 50 persen kuota harian Workers KV, dan kalau sampai habis sebelum jam reset, semua permintaan ke storage itu bakal ditolak. Reaksi pertama saya jelas, worker mana yang traffic-nya tiba tiba melonjak.
Ternyata dugaan saya salah total. Salah satu worker saya menjalankan beberapa proses otomatis lewat cron trigger, cek pesan pembeli tiap 5 menit, cek pesan mitra kreator tiap 15 menit, sinkronisasi stok tiap 30 menit. Setiap kali salah satu proses ini selesai, kodenya menulis ringkasan hasil ke KV, semacam catatan terakhir jalan kapan dan hasilnya apa, tanpa syarat, bahkan saat tidak ada satu pun pesan atau perubahan stok. Kalau dihitung, cek pesan pembeli saja menyumbang 288 kali tulis per hari, cek mitra kreator 96 kali, sinkron stok 48 kali. Totalnya sekitar 434 tulisan per hari hanya untuk mencatat status, sementara kuota gratisnya cuma 1.000 tulisan per hari.
Kalau dicocokkan dengan penjelasan di atas, ringkasan status itu jelas kebalikan dari yang KV rancang, dia berubah setiap beberapa menit, dan cuma dibaca sesekali saat saya iseng mengecek endpoint status. Pola tulis sering baca jarang ini seharusnya masuk ke D1, bukan KV.
Perbaikan yang saya ambil
Karena kebutuhan sebenarnya cuma sekadar tahu worker ini masih hidup, terakhir jalan kapan, saya putuskan tidak menambah komponen baru sama sekali. Saya ubah syarat penulisannya, KV hanya ditulis kalau memang ada aktivitas nyata:
if (unread.length > 0 || errors.length > 0) {
await env.CREDS.put(CS_CHECK_LAST_RUN_KEY, JSON.stringify(summary));
}
Saat proses berjalan kosong, cukup dicatat lewat console.log biasa, yang otomatis bisa dilihat lewat Cron Events dan Workers Logs bawaan Cloudflare, gratis, tanpa menyentuh kuota apa pun. Jadwal cron tidak saya ubah sama sekali, cek pesan pembeli tetap tiap 5 menit seperti sebelumnya.
Yang membuat saya berhenti sejenak justru bukan soal solusinya, tapi soal betapa mudahnya kebiasaan kecil seperti ini lolos tanpa disadari. Kode yang menulis ringkasan status itu sudah ada cukup lama, jalan normal, tidak pernah error, sampai akhirnya kuota yang jadi korbannya. Sejak itu saya jadi lebih terbiasa bertanya dulu sebelum menyimpan data ke suatu tempat, seberapa sering data itu akan dibaca dibanding ditulis, dan apakah memang butuh cepat diakses dari mana saja atau cukup benar di satu tempat. Pertanyaan sederhana itu yang akhirnya menentukan storage mana yang benar benar tepat, bukan sekadar mana yang paling gampang dipasang.