Kadang penghematan infrastruktur terbesar datang dari baris yang paling membosankan: layout sebuah struct. Tanggal 18 September 2026, tim Cloudflare menerbitkan post-mortem optimasi di blog mereka berjudul "Saving another 100TB of RAM with math (and Rust)". Angkanya bukan typo. Dua perubahan kecil pada implementasi consistent hashing di satu layanan berbasis Pingora memangkas penggunaan RAM mereka lebih dari 100TB secara global,ditambah penghematan 100TB yang sebelumnya dilakukan tim DNS. Ini cerita teknisnya, dan kenapa setiap engineer yang menyentuh Rust atau manajemen memori harus membacanya.
Posting aslinya ditulis Kevin Guthrie, Mariia Iurchenko, Zaidoon Abd Al Hadi, dan Ivan Babrou, ada di blog.cloudflare.com. Semua perubahan yang diceritakan sudah tersedia di crate pingora-ketama.
Konteks: Consistent Hashing Itu Apa dan Kenapa Makan RAM
Cloudflare memakai consistent hashing untuk merutekan request yang bisa di-cache ke server berdasarkan URL, sehingga satu file cukup disimpan satu kali per data center dan letaknya selalu bisa dicari secara stabil. Model mentalnya: ruang hash (di sini 32-bit) dibentangkan jadi garis angka, tiap server menempatkan sejumlah titik di sepanjang garis itu, dan sebuah request jatuh ke titik terdekat searah jarum jam.
Kualitas distribusi bergantung pada banyaknya titik per server. Makin banyak titik, makin merata bagiannya. Di sinilah tagihan RAM datang: setiap titik adalah satu entri di memori, dan entri itu dikalikan titik per server, dikalikan jumlah server, dikalikan semua cluster yang menjalankan struktur ini. Scale mengubah byte kecil menjadi petabyte.
Perbaikan 1: Struct yang Membengkak oleh Aturan Alignment
Representasi awal sebuah titik di layanan itu begini:
struct Point {
hash: u32,
index: u32,
}
Delapan byte per titik: empat untuk hash (tidak bisa dihindari), empat sebagai indeks ke array server. Insight pertama, dari Zaidoon: indeks 32-bit itu berlebihan. Pusat data tidak mungkin mengoordinasi lebih dari 2 pangkat 16, sekitar 65 ribu server, sekaligus. Tipe u16 lebih dari cukup.
Tapi mengganti field kedua menjadi u16, secara naif, tidak menghemat sepeser pun. Aturan alignment Rust menuntut ukuran struct menjadi kelipatan field paling aligned-nya. Field terbesar, hash, empat byte, jadi struct tetap harus berukuran kelipatan empat: delapan byte, dengan byte yang terbuang sebagai padding. Kelas yang sama, pemborosan yang sama, tanpa perubahan apa pun.
Dua jalan keluar yang dibahas post tersebut: atribut #[repr(packed)], yang kontroversial karena alasan-alasan bagus (referensi ke field unaligned bisa jadi undefined behavior di platform tertentu), atau pendekatan yang kurang glamor tapi aman: menyimpannya sebagai array byte mentah dengan getter.
struct Point([u8; 6]);
impl Point {
fn hash(&self) -> u32 {
u32::from_ne_bytes(self.0[0..4].try_into().unwrap())
}
fn index(&self) -> u16 {
u16::from_ne_bytes(self.0[4..6].try_into().unwrap())
}
}
Delapan byte jadi enam. Hemat 25 persen dari struktur titiknya, hanya dari kompresi data, tanpa mengubah algoritma apa pun. Di atas kertas tidak dramatis; di atas ratusan miliar titik, sangat dramatis.
Perbaikan 2: Matematika yang Menghukum "Sekalian Banyakin Titik Aja"
Bagian yang membuat judul "with math" bukan clickbait. Distribusi titik per server punya deviasi standar; makin banyak hash per server, makin rata bagiannya, tapi dengan kurva yang sangat kejam. Tim-nya menurunkan rumus eksak (derivasinya diposting terpisah, bukan sekadar approximation dari textbook) untuk kasus k hash per server, lalu melihatnya lewat koefisien variasi.
Kesimpulan angka yang mereka publish: dengan basis 160 titik per satuan bobot penyimpanan, sebuah server berbobot 625 bisa memegang 100.000 titik. Dari chart koefisien variasi, 90.000 titik terakhir dari 100.000 itu hanya membeli pengurangan error sekitar 0,7 persen. Nyaris gratis? Tunggu, ada twist yang lebih kejam.
Model kontinu itu mengasumsikan ruang hash tak terbatas. Praktiknya, hash-nya 32-bit, dan begitu jumlah titik per server membesar, probabilitas tabrakan antar titik meroket mengikuti birthday paradox. Tabrakan berarti sebagian titik tidak ikut mendistribusikan beban, error-nya acak dan tidak hilang meski titiknya ditambah. Di simulasi untuk data center dengan 2048 server, error justru naik di rentang 10.000 sampai 100.000 titik per server.
Soal yang selama ini dianggap fitur ("makin banyak titik makin aman") ternyata sebagian besar sampah memori. Dengan bekal matematika itu, Cloudflare memangkas jumlah hash per server sebesar 90 persen tanpa degradasi error yang terukur. Ring-ring hash besar yang kini tidak terpakai didecommissioned selamanya.
Yang Paling Berisiko: Migrasi Tanpa Melelehkan Origin
Judul seksi blog-nya: "Migrating without melting origins". Ganti komposisi titik berarti mengubah sebagian jalur routing, dan traffic yang pindah itu berarti cache yang sudah hangat menjadi dingin di tujuan baru. Cache-cold dalam skala besar berarti fetch ulang ke origin server, lonjakan beban, dan potensi kegagalan berantai. Rilis struktur baru yang lebih hemat harus dilakukan bertahap dan terkontrol, fase di mana disiplin ops lebih menentukan daripada cleverness kode. Mereka tidak menjabarkan angkanya di bagian yang dikutip publik, tapi framing seksinya jujur: menghemat RAM itu bagian mudah; memindahkan peta routing produksi adalah bagian berbahaya.
Tiga Pelajaran untuk Diambil
- Audit layout memori sebelum scale-out. Empat byte padding per entri terasa gratis sampai dikalikan ratusan miliar entri. Pola yang sama berlaku untuk index database, format kolom di data lake, dan metadata di mana pun: tanya dulu berapa byte, baru berapa baris.
- Kurangi, jangan tambah. Insting engineers saat error sedikit naik adalah menambah buffer, retry, atau titik hash. Data menunjukkan kurva diminishing return yang ekstrem di struktur ini. Sebelum menambah resource, ukur dulu kontribusi marginalnya.
- Birthday paradox meraja di ruang hash terbatas. Tiap desain yang menempelkan banyak entri ke ruang 32-bit punya plafon yang tidak bisa dinaiki dengan menambah entri.
Penutup
Total dari pemadatan struct 25 persen dan pemangkasan 90 persen titik, ditambah membereskan peninggalan ring lama: lebih dari 100TB RAM kembali ke resource pool, di atas 100TB yang sudah dihemat tim DNS bulan sebelumnya. Tidak ada hardware baru, tidak ada rewrite layanan, tidak ada model AI yang menentukan konfigurasi. Satu struct, satu rumus, dan keberanian memvalidasi asumsi lama bahwa lebih banyak titik selalu lebih baik. Buat yang penasaran dengan implementasinya: semuanya hidup di crate pingora-ketama, saat posting diterbitkan masih di balik feature flag cargo yang "belum diiklankan". Cara paling Cloudflare untuk merilis sesuatu yang mengubah peta biaya.
Hitung-hitungan Kenapa Ini Jadi Uang Sungguhan
Biar terasa konkret, aritmetika sederhananya. Bayangkan satu cluster dengan 2.048 server dan struktur titik yang disimpan untuk setiap bobot penyimpanan. Pada konfigurasi lama, sebuah server berbobot tinggi bisa memegang 100.000 titik. Delapan byte dikali 100.000 titik dikali 2.048 server sudah mendekati 1,6GB untuk satu salinan ring; layanan menjalankan banyak instans, banyak cluster, banyak region, dan struktur yang sama ada di mana-mana. Sekarang kalikan dengan fleet yang tersebar di ratusan kota. Dari situlah angka 100TB datang; bukan dari satu tabel besar, tapi dari pengulangan struktur kecil sampai skala yang membuat byte menjadi ton.
Yang juga sering terlewat: memori itu hidup di mesin edge yang bekerja di titik-titik termurah secara per-gigabyte, dan Cloudflare menyebut motivasi post ini secara blak-blakan, berbagi sumber daya antar tim yang adil. Mengembalikan 100TB ke pool berarti ada 100TB yang bisa dipakai tim lain tanpa purchase order. Di skala itu, optimasi algoritma dan negosiasi hardware adalah mata uang yang sama.
Jebakan Rust yang Wajib Lo Tahu dari Kasus Ini
Dua pelajaran bahasa yang relevan bahkan kalau lo tidak menyentuh consistent hashing. Pertama, repr(packed) memang terlihat seperti jawaban cepat untuk pemborosan padding, tapi komunitas Rust menyebutnya kontroversial dengan alasan yang konkret: mengambil referensi ke field yang tidak aligned adalah undefined behavior, dan compiler hanya bisa menjaga lo sampai batas tertentu. Alternatif array byte dengan getter yang dipakai Cloudflare terasa verbose, tapi ia tidak punya jebakan tersembunyi: lo membaca dan menulis angka dari buffer, tanpa jebakan alignment. Compiler mengompilasi keduanya ke kode mesin yang setara untuk kasus ini, jadi tidak ada trade-off performa.
Kedua, perhatikan from_ne_bytes dalam snippet: native-endian. Aman untuk struktur yang tidak pernah dikirim lewat jaringan atau disimpan lintas mesin. Begitu titik data yang sama keluar dari proses, pindah ke arsip, atau melintasi wire, lo wajib memutuskan endianness secara eksplisit, bukan mewariskannya dari CPU tempat build berjalan. Bug lintas-platform jenis ini legendaris.
Yang Bisa Lo Ambil untuk Sistem Sendiri
Tidak perlu punya edge network untuk mengambil nilai post ini. Rutenya: profil memori alokasi struktural lo, bukan cuma CPU. Di aplikasi dengan banyak cache entry, index in-memory, atau metadata per item, jalankan profiler alokasi dan tanya berapa byte per entry dan berapa banyak entry. Kalau jawabannya satu entri lebih dari tiga digit byte padahal data aslinya muat di dua digit, cari padding-nya. Lalu curigai insting scaling-by-noise: kalau kualitas membaik dengan menambah titik, entri, retry, atau salinan, plot kurva improvement-nya; bagian yang datar adalah tempat pemborosan hidup. Cloudflare membayar pelajaran ini dengan ring yang tidak perlu selama bertahun-tahun, dan membayarnya kembali dengan matematika. Yang mereka butuhkan cuma keberanian untuk memvalidasi asumsi warisan.
Sumber
- Cloudflare Blog, 18 September 2026: Saving another 100TB of RAM with math (and Rust), Kevin Guthrie dkk. 13 menit baca
- Crate pingora-ketama (open source) sebagai tempat perubahan dirilis
💬 Komentar (0)
Belum ada komentar. Jadilah yang pertama! 💬