Oyuncu

Cloudflare beş kod değişikliğiyle 250 milyar DNS kaydını optimize etti

GTA6
×

Cloudflare beş kod değişikliğiyle 250 milyar DNS kaydını optimize etti

Share this article


Cloudflare, 1.1.1.1’in de aralarında bulunduğu DNS servislerini çalıştıran Big Pineapple platformunda yaptığı beş ayrı Rust optimizasyonuyla yaklaşık 100 TB belleği serbest bıraktı. Her an 250 milyardan fazla DNS önbellek kaydı tutan sistemde kayıt başına bellek tüketimi 953 bayttan 420 bayta indi.

Üstelik tasarruf performans kaybıyla gelmedi, önbelleğe kayıt ekleme hızı yüzde 43 arttı, sorgulardaki arama gecikmesi yüzde 19 düştü. Serbest kalan bellek, Cloudflare’ın 130 adet Gen 13 sunucusunda bulunan toplam RAM kapasitesine yakın.

250 milyar DNS kaydında tek bir bayt bile 250 GB RAM demek

Cloudflare’ın Big Pineapple adını verdiği platform yalnızca 1.1.1.1 genel DNS çözümleyicisini çalıştırmıyor. Gateway DNS, DNS Firewall, AS112 ve şirketin diğer bazı DNS hizmetleri de aynı altyapıyı kullanıyor.

Cloudflare beş kod değişikliğiyle 250 milyar DNS kaydını optimize etti

Sistem herhangi bir anda 250 milyardan fazla önbellek kaydını bellekte tutuyor. Bu ölçekte her kayıt üzerinde gereksiz kullanılan yalnızca 1 bayt, sunucu filosunun tamamında 250 GB’tan fazla RAM tüketiyor.

Big Pineapple yeniden başlatıldığında önbellek boş durumda başlıyor. DNS sorguları geldikçe yeni yanıtlar belleğe ekleniyor ve belirlenen maksimum kayıt sayısına ulaşıldığında daha eski ya da daha az kullanılan kayıtlar çıkarılarak yer açılıyor.

Önbelleğin büyüklüğü veri merkezine göre değişiyor. EDNS Client Subnet, yani ECS kullanılan noktalarda aynı sorgunun istemcinin ağına bağlı farklı yanıtları bulunabildiği için aynı DNS sorgusunun birden fazla sürümünün saklanması gerekiyor. Bu veri merkezlerinde hem kayıt sayısı hem de kayıtların kapladığı toplam alan daha yüksek.

Her önbellek girdisi temel olarak bir anahtar-değer çiftinden oluşuyor. Anahtar bölümünde sorgulanan alan adı, DNS kayıt türü, yanıtın doğrulanmış olup olmadığı ve ECS gibi durumlarda kullanılan etiket bulunuyor.

Değer tarafında ise DNS yanıtının answer, authority ve additional bölümleriyle birlikte oluşturulma zamanı, TTL süresi, kullanım sayacı ve hata bilgileri gibi veriler saklanıyor.

Cloudflare’ın yaptığı inceleme, bu yapılarda bir kez önbelleğe girdikten sonra artık ihtiyaç duyulmayan çeşitli ek kapasite ve veri alanlarının bulunduğunu ortaya çıkardı.

Değişikliklerin etkisini ölçmek için üretim trafiğine yakın bir test ortamı oluşturuldu. Test kayıtlarının yüzde 56’sı IPv4 adresleri için kullanılan A, yüzde 25’i IPv6 için kullanılan AAAA ve yüzde 19’u TXT kayıtlarından oluştu.

Her önbellek girdisine bir ile dört arasında DNS kaydı yerleştirildi. Değişken uzunluktaki diğer DNS türlerini temsil eden TXT kayıtlarının boyutu da 64 ile 224 bayt arasında değiştirildi.

Bellek tahsislerinin sayısı ve boyutu Rust’ın System allocator’ını saran özel bir allocator ile izlendi; bunun yanında ekleme performansı ve sorgu gecikmesi de ölçüldü. Test sonuçları daha sonra gerçek üretim sunucularındaki yerleşik bellek kullanımıyla karşılaştırıldı.

İlk büyük tasarruf Rust’taki Vec ve String yapılarının değiştirilmesiyle geldi. Vec bellekte veri işaretçisi, mevcut uzunluk ve ileride büyümek için ayrılmış kapasite bilgisini tutuyor.

Ancak DNS yanıtı önbelleğe girdikten sonra değiştirilmiyor. Dolayısıyla büyüme için ayrılan kapasiteye artık ihtiyaç kalmıyor. Cloudflare bu alanlarda büyüyebilen Vec yerine sabit boyutlu Box<[T]>, String yerine de Box kullanmaya başladı.

Tek bir önbellek girdisinde bu tür sekiz Vec veya String alanı bulunuyordu. Her alandaki kapasite bilgisinin kaldırılması 8 bayt, toplamda kayıt başına 64 bayt tasarruf sağladı.

Vec yapıların ileride kullanılmak üzere fazladan ayırdığı heap alanının da ortadan kalkmasıyla yalnızca bu değişikliğin 250 milyardan fazla kayıtta sağladığı tasarruf 15 TB’ı geçti.

Bir başka değişiklik DNS yanıtının answer, authority ve additional bölümlerinin bellekte nasıl tutulduğuyla ilgiliydi. Daha önce bu üç bölüm ayrı listelerde saklanıyordu. Yeni yapıda tüm kayıtlar tek bir listede tutulmaya, bölümlerin başladığı konumlar ise offset değerleriyle işaretlenmeye başladı.

DNS bölümlerindeki kayıt sayıları u16 sınırları içine sığdığı için her offset yalnızca 2 bayt kaplıyor. İki ayrı listenin 8 baytlık işaretçileri ve 8 baytlık uzunluk bilgilerinin kaldırılması kayıt başına 28 bayt daha kazandırdı. Bazı boolean değerlerin tek bir bitflag içinde birleştirilmesi de Rust’ın veri hizalama için eklediği padding alanlarını küçülttü.

DNS kayıtlarındaki alan adlarında da önemli miktarda tekrar bulunuyordu. Her DNS kaydının bir owner alanı var ve bu alan çoğu zaman sorgulanan alan adıyla aynı.

Örneğin example.com için yapılan standart bir A sorgusunda dönen A kayıtlarının owner bilgisi de example.com oluyor. CNAME kullanılan sorgularda ise zincirin sonraki aşamalarındaki kayıtların sahibi farklı bir alan adı olabiliyor.

DNS’in ağ üzerinden kullanılan wire formatı bu tür tekrarları zaten sıkıştırıyor. RFC 1035’te tanımlanan DNS name compression sistemi, daha önce mesaj içinde geçen bir alan adını tekrar yazmak yerine 2 baytlık bir işaretçi kullanabiliyor.

Cloudflare’ın önbelleğinde ise sorgu sırasında bu işaretçileri takip etmenin getireceği işlem maliyetini azaltmak için kayıt sahipleri daha önce eksiksiz biçimde tutuluyordu. Yeni düzende owner sorgulanan alan adıyla aynıysa isim ayrıca saklanmıyor.

Yanıt hazırlanırken alan adı önbellek anahtarından yeniden alınıyor. CNAME sonrasındaki A kaydı gibi gerçekten farklı owner kullanan kayıtların alan adı ise bellekte tutulmaya devam ediyor.

Bellek tüketimindeki en dikkat çekici noktalardan biri Rust enum yapılarından kaynaklanıyordu. Enum içindeki farklı türler farklı miktarda veri taşıyabilse de bellekteki enum boyutu en büyük varyanta göre belirleniyor.

DNS kayıtlarını temsil eden yapıda en büyük türlerden NAPTR tek başına 136 baytlık veri içeriyor. Varyant etiketi ve hizalama alanları eklendiğinde RecordData enumunun büyüklüğü 144 bayta çıkıyordu.

Buna karşılık internette en sık kullanılan A kaydı yalnızca 4 baytlık IPv4 adresi, AAAA ise 16 baytlık IPv6 adresi taşıyor. A ve AAAA kayıtları Cloudflare trafiğinin yüzde 80’den fazlasını oluşturmasına rağmen her biri 144 baytlık enum içinde tutulduğu için kayıt başına 120 bayttan fazla alan kullanılmadan kalabiliyordu. Tek bir DNS önbellek girdisinin birden fazla kayıt içerebilmesi farkı daha da büyütüyordu.

Cloudflare önce büyük enum varyantlarını ayrı heap tahsislerine taşıdı. A ve AAAA gibi küçük ve sık kullanılan kayıtlar doğrudan yapının içinde kalırken TXT, NAPTR ve SVCB gibi daha büyük türler bir işaretçi üzerinden ayrı bellekte tutuldu.

Böylece A ve AAAA kayıtlarında kayıt başına 120 bayt tasarruf edildi. TXT ve CNAME gibi türler de 144 bayta tamamlanmak yerine gerçek veri boyutlarına uygun miktarda alan kullanmaya başladı. Nadir karşılaşılan NAPTR ise yeni işaretçi ve heap tahsisinin maliyeti nedeniyle az miktarda daha fazla bellek tüketti.

Ancak bu yöntemin başka bir maliyeti vardı. Big Pineapple’ın kullandığı jemalloc, heap tahsislerini belirli boyut sınıflarına yuvarlıyor. Örneğin 32 bayt isteyen bir TXT kaydı 32 baytlık sınıfa tam otururken 40 baytlık bir MX kaydı 48 baytlık alana yerleştiriliyor ve 8 bayt boş kalıyor.

Ayrı ayrı boxing işlemi ayrıca DNS kayıtlarını belleğin farklı noktalarına dağıtıyor. CPU bir kaydı okurken başka bir bellek bölgesine gidip yeni cache line getirmek zorunda kalabiliyor ve memory locality düşüyor.

Beşinci değişiklikte bu sorun da ele alındı. DNS yanıtının tamamını hazır wire formatında saklamak tercih edilmedi. DNSSEC kayıtlarının istemcinin DO, yani DNSSEC OK bayrağına bağlı olarak yanıta eklenmesi, tam mesajın saklanması halinde DNSSEC’li ve DNSSEC’siz iki ayrı sürüm bulundurmayı ya da hazırlanmış mesajın sonradan filtrelenmesini gerektirecekti. Tam DNS mesajının her sorguda yeniden ayrıştırılması da ek işlem yükü oluşturacaktı.

Bunun yerine yalnızca DNS kayıt verileri ham wire formatında saklanmaya başladı. Ayrıştırılmış enum listelerinin yerini tek bir Box<[u8]> aldı. Her kayıt bu tampon içinde 2 baytlık uzunluk bilgisi ve hemen arkasından gelen ham DNS verisiyle tutuluyor.

Ayrı enumların ve her kayıt için oluşturulan heap tahsislerinin ortadan kalkması verilerin bellekte yan yana yerleşmesini sağladı. Rastgele bir kayda doğrudan erişmek yerine tamponun sırayla okunması gerekiyor ancak önbellek girdilerindeki kayıt sayısı düşük olduğu için bunun maliyeti sınırlı kaldı. A ve AAAA kayıtlarının round-robin sıralaması gibi bazı işlemlerin uygulanması ise biraz daha karmaşık hale geldi.

A, AAAA, TXT ve DNSSEC kayıtları artık yanıt oluşturulurken alan alan yeniden serileştirilmek yerine önbellekteki ham veriden doğrudan çıkış mesajına kopyalanabiliyor.

CNAME, NS, MX ve SOA gibi içinde alan adı bulunan türlerde DNS name compression uygulanabilmesi için ayrıştırma işlemi devam ediyor. Ham kayıt düzenine geçiş ve artan memory locality tek başına önbellek sorgu gecikmesini testlerde yüzde 5 azalttı.

Kayıt ekleme tarafında ise yeniden kullanılabilen geçici bir buffer kullanılmaya başladı. Bu tampon önceki işlemlerde zaten büyümüş olduğu için çoğu yeni eklemede tekrar bellek tahsis etmeye ihtiyaç duymuyor.

Tüm kayıtlar hazırlandıktan sonra gerekli boyutta tek bir Box<[u8]> oluşturuluyor ve veri tek seferde buraya kopyalanıyor. Önceki yöntemdeki her kayıt için ayrı allocation işlemleri ortadan kalkarken küçültülen Vec yapılarından kalan kullanılamayan alanlar da giderildi. Bu değişiklik tek başına önbelleğe kayıt ekleme performansını yüzde 13 artırdı.

Optimizasyonların üretim ortamına dağıtılması 18 Mayıs 2026’da başladı ve 6 Temmuz 2026’da tüm hizmetlerde tamamlandı. Değişiklikler tek sürümde devreye alınmadığı için sunuculardaki bellek tüketimi aşamalı şekilde düştü.

Yeniden başlatılan Big Pineapple örnekleri ilk anda boş önbellekle çalıştığından başlangıçtaki bellek değerleri düşük kaldı; önbellekler dolduktan sonraki kararlı değerler gerçek çalışma yükünü gösterdi.

Üretim ortamında p99 seviyesindeki örnek başına yerleşik bellek kullanımı 9,3 GB’tan 5,3 GB’a indi ve yüzde 43 azaldı. p90 seviyesinde ise 6,5 GB’tan 3,8 GB’a gerileyerek yüzde 42 düşüş kaydedildi. Önbelleği daha dolu çalışan sunucularda mutlak bellek kazancı daha yüksek oldu.

Beş optimizasyon birlikte değerlendirildiğinde testlerde tek bir DNS önbellek girdisinin net bellek maliyeti 953 bayttan 420 bayta indi; düşüş yüzde 56’ya ulaştı. Kayıt başına yapılan toplam bellek tahsisi de 1,1 KB’tan 461 bayta gerileyerek yüzde 58 azaldı.

Üretim sunucularında süreçlerin yalnızca DNS önbelleğini değil diğer verileri de bellekte tutması nedeniyle toplam RAM kullanımındaki yüzdesel düşüş daha düşük kaldı. Tüm sunucu filosundaki çalışma setinde serbest kalan kapasite yaklaşık 100 TB oldu.

Performans rakamlarında da aynı anda artış kaydedildi. Önbelleğe veri ekleme kapasitesi saniyede 625 bin kayıttan 893 bin kayda çıkarak yüzde 43 yükseldi. Önbellekte bir kaydı bulma gecikmesi 828 nanosaniyeden 670 nanosaniyeye indi ve yüzde 19 azaldı.

Yaklaşık 100 TB’lık kapasite Cloudflare’ın 130 adet Gen 13 sunucusunda bulunan belleğe karşılık geliyor. Şirketin Gen 13 sistemlerinde 12 adet 64 GB DDR5-6400 ECC RDIMM bulunuyor ve her sunucu toplam 768 GB RAM taşıyor.

Gen 13 platformunda ayrıca 192 çekirdekli AMD EPYC 9965 işlemci, 24 TB PCIe 5.0 NVMe depolama ve çift 100 GbE ağ bağlantısı kullanılıyor.

Serbest kalan RAM fiziksel sunuculardan çıkarılmayacak. Big Pineapple’ın DNS önbellek kapasitesi aynı bellek bütçesi içinde büyütülecek. Daha fazla DNS yanıtının önbellekte kalması cache hit oranını artıracak ve yetkili DNS sunucularına gönderilen üst seviye sorgu sayısını azaltacak. Önbellek yapısı üzerinde yeni optimizasyon çalışmaları da devam edecek.



Kaynak

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir