← Teknoloji Radarı

Altyapı

Cloudflare 100 TB belleği nasıl kurtardı? Veri yapısında küçük değişiklikler

Cloudflare, 1.1.1.1 DNS servisinin önbelleğindeki her kaydın bellek ihtiyacını %56 azalttı. Toplamda yaklaşık 100 terabayt RAM boşa çıktı ve sorgular hızlandı. Hepsi Rust kodunda birkaç akıllı düzenlemeyle.

Bu neden önemli?

Küçük bir veri yapısındaki birkaç bayt, milyarlarca kez tekrarlandığında dev bir faturaya dönüşür. Bu hikâye, belleğin aslında nasıl kullanıldığını anlamak için güzel bir ders.

Cloudflare Just Saved 100TB of Memory · Better Stack, YouTube (İngilizce). Tıklayınca video yüklenir.

1.1.1.1 ne yapıyor?

Tarayıcına bir site adresi yazdığında, bilgisayarın önce o adın hangi IP adresine karşılık geldiğini öğrenmek zorunda. Bu işi DNS yapıyor. İnternetin telefon rehberi gibi.

Cloudflare’in 1.1.1.1 servisi, dünyanın en çok kullanılan ücretsiz DNS çözümleyicilerinden biri. Her seferinde gidip asıl kaynağa sormamak için cevapları bir önbellekte tutuyor. Cloudflare’e göre bu önbellekte 250 milyardan fazla kayıt var, dünya genelindeki sunucularına dağılmış hâlde.

Bu ölçekte her kayıttaki birkaç bayt bile önemli. Ağustos sonunda yayınlanan yazıya göre bir kaydın ortalama boyutu 953 bayttan 420 bayta indi.

Beş değişiklik, sade anlatımla

Kod Rust ile yazılmış. Yapılan değişikliklerin ortak fikri: Kullanılmayan alanları ve gereksiz işaretçileri atmak.

1. “Büyüyebilir” listeleri sabitlemek. Rust’ta Vec ve String, sonradan eleman eklenebilsin diye kendi kapasitesini de ayrıca tutar. Ama önbelleğe giren bir DNS cevabı bir daha değişmiyor. Bunları sabit boyutlu Box türlerine çevirmek, kayıt başına yaklaşık 64 bayt kazandırdı. Uzamayacak bir liste için “uzarsa diye” yer ayırmanın anlamı yok.

2. Üç listeyi teke indirmek. Bir DNS cevabında üç ayrı bölüm vardır. Her biri ayrı bir listede tutuluyordu. Hepsini tek listede toplayıp bölümlerin nerede başladığını 8 baytlık işaretçiler yerine 2 baytlık küçük sayılarla işaretlemek 28 bayt daha kazandırdı.

3. Tekrarı atmak. Her kayıtta sorulan alan adının bir kopyası daha saklanıyordu. Çoğu zaman bu ad, zaten sorulan adın aynısı. Artık sadece farklıysa saklanıyor.

4. Nadir büyük kayıtları kenara almak. Rust’ta bir enum (birkaç farklı türden birini tutabilen yapı), en büyük seçeneği kadar yer kaplar. Nadiren kullanılan büyük kayıt türleri yüzünden sık kullanılan küçük türler de şişiyordu. Büyükleri ayrı bir kutuya taşıyınca, yaygın A ve AAAA kayıtları küçüldü.

5. Veriyi ağdan geldiği gibi saklamak. Son adımda kayıtlar, DNS’in kendi ağ formatındaki ham baytlar olarak tek bir bellek bloğunda tutulmaya başlandı. Veri bellekte daha derli toplu durunca işlemci de ona daha hızlı ulaşıyor.

Sonuç

Cloudflare’in paylaştığı rakamlar:

  • Kayıt başına bellek: %56 daha az.
  • Toplam kazanç: yaklaşık 100 terabayt RAM.
  • Önbelleğe ekleme hızı: %43 daha fazla.
  • Arama süresi: %19 daha kısa.

Yani daha az bellek, bu kez daha yavaş değil, daha hızlı sistem demek. Veri küçüldükçe işlemcinin kendi hızlı önbelleğine daha çok şey sığıyor.

Erken optimizasyon mu?

Yazılımda ünlü bir söz vardır: “Erken optimizasyon her kötülüğün anasıdır.” Video da bunu tartışıyor. Buradaki durum farklı: Kazanç kayıt başına ölçülebilir bir rakam ve 250 milyar kayıtla çarpılınca devasa bir sonuca dönüşüyor. Kendi projende aynı titizliğe muhtemelen gerek yok. Ama “bu alan gerçekten gerekli mi?” sorusu her ölçekte işe yarar.

Düşün

  • Yazdığın bir programda bir nesne bir milyon kez oluşturulsa, içindeki hangi alanlar gereksiz kalırdı?
  • Bir optimizasyona zaman ayırmadan önce neyi ölçmek isterdin?