UDP üzerinden yayınlanan bir veri akışında yaklaşık %30 oranında paket kaybı yaşanıyordu. Hata mesajları, istisnalar ya da stack trace’ler yoktu — sadece eksik sıra numaraları dikkat çekiyordu. İlk şüphe genellikle network’e yöneltilir: arızalı bir switch, doymuş bir bağlantı hattı ya da yorgun bir ağ arayüz kartı. Ancak bu vakada durum farklıydı.
Network suçsuzdu. Paketler alıcı bilgisayara ulaştıktan sonra kaybediliyordu. Peki bu farkı nasıl anlayabilirsiniz ve neden önemli?
UDP’nin gizli tehlikesi: Sessiz kayıplar
UDP, güvenilir bir protokol değildir. Paket kaybı durumunda ne gönderen ne de alan taraf uyarılır. Basitçe, paket yok olur gider. Uygulama katmanından bakıldığında, bu iki tamamen farklı sorun aynı şekilde görünür:
- Paket, makinenize ulaşmadan önce network tarafından kaybedilmiş olabilir.
- Paket makinenize ulaştıktan sonra işletim sistemi tarafından reddedilmiş olabilir.
Uygulama açısından sonuç aynıdır: eksik bir sıra numarası. Ancak çözüm tamamen farklı bir yerde aranmalıdır.
Paketlerin akibeti: Network’ten RAM’e yolculuk
Bir UDP paketinin yolculuğu şu adımlardan oluşur:
- Ağ arayüz kartı (NIC) tarafından alınması
- Kernel’in socket receive buffer’ına yerleştirilmesi
- Uygulamanın
recv()fonksiyonu tarafından okunması
Kernel, gelen datagramları socket buffer’ında saklar. Eğer uygulama bu buffer’dan veriyi yeterince hızlı okumazsa, buffer dolmaya başlar. Tamamen dolan buffer, yeni gelen paketleri reddeder. Bu kayıplar, kernel tarafından sayılır ve kaydedilir.
Linux sistemlerinde bu kayıpları tespit etmek için aşağıdaki komutlar kullanılabilir:
# Protokol bazında genel istatistikler
netstat -su
# Kernel sayaçlarını doğrudan okuma
cat /proc/net/snmp | grep -A1 UdpBu komutların çıktısında InDatagrams alındı paket sayısını, InErrors hata sayısını ve RcvbufErrors ise receive buffer’ından dolayı kaybedilen paket sayısını gösterir. Eğer RcvbufErrors değeri artıyorsa, network görevini yerine getirmiş ancak makinenizin buffer’ı dolmuş demektir.
Gerçek sebep: Buffer kapasitesi ve işleme hızı uyumsuzluğu
Bu vakada socket receive buffer’ı varsayılan değer olan yaklaşık 208 KB’ta sabitlenmişti. Gönderen taraf, alıcıdan daha hızlı veri gönderiyordu. Tek bir thread’in recv() fonksiyonu aracılığıyla buffer’dan veri okuma hızı, gelen paketlerin akış hızını karşılamıyordu. Ortalama veri aktarım hızı dashboard’larda normal görünse de, ani veri patlamaları (burst’ler) buffer’ı milisaniyeler içinde dolduruyor ve fazlası kaybediliyordu.
Önemli olan metriğin ortalama veri hızı değil, ani veri patlamalarının buffer’ı doldurma hızı ile buffer’ın boşaltılma hızı arasındaki dengedir.
Çözüm önerileri: Sırayla uygulanan adımlar
- Daha hızlı veri okuma. Alıcı uygulama, alınan veriyi doğrudan parse ediyor ve veritabanına kaydediyordu. Bu işlemler
recv()fonksiyonunun hemen ardından gerçekleştiğinde, buffer’ın boşaltılması gecikiyordu. Çözüm:recv()fonksiyonu sadece buffer’dan veri okusun, ardından bu veriyi ayrı bir kuyruğa aktarsın ve hemen yeni birrecv()çağrısına geçsin.
- Buffer boyutunu artırma.
SO_RCVBUFayarını yükseltin ve kernel’in bu talebi gerçekten uygulaması içinnet.core.rmem_maxdeğerini de artırın. Daha büyük bir buffer, yavaş bir tüketiciyi düzeltmez ancak ani patlamaları absorbe ederek tüketici yeterince hızlıysa buffer’ın dolmamasını sağlar. Genellikle her iki adım da gereklidir.
- Sistem çağrılarını toplu işlemek. Yüksek hacimli durumlarda,
recvmmsg()fonksiyonu birden fazla datagramı aynı sistem çağrısıyla alabilir. Bu sayede her paket için yapılan sistem çağrısı masrafı azalır.
- Yükü dağıtma. Tek bir çekirdek yeterli performansı sağlayamıyorsa,
SO_REUSEPORTözelliği aynı portu paylaşan ve ayrı buffer’lara sahip çoklu thread’lere izin verir.
Önemli çıkarımlar
- "Paket kaybı" bir konumdur, bir sebep değildir. Teoriler üretmeden önce kaybın nerede meydana geldiğini belirleyin.
- UDP sessiz kayıplara izin verir — protokol size haber vermez, bu yüzden kernel sayaçlarına güvenmek zorundasınız.
- İlk kontrol edilecek şey
RcvbufErrorssayacıdır. Neredeyse her zaman ya buffer’ın yetersiz boyutta olması ya da tüketici hızının yavaş olmasıyla ilişkilidir. - Daha büyük bir buffer ani patlamaları absorbe eder; daha hızlı bir tüketici kayıpları önler. Genellikle her ikisine de ihtiyaç vardır.
Bu vakanın tam debugging süreci, buffer hesaplamaları ve ayarlama sırasında izlenen kernel sayaçlarıyla birlikte Medium’da paylaşılıyor. Ayrıntılar için The Speed Engineer tarafından yazılan "Networking for Developers: I Lost 30% of UDP Packets — The Debugging Story" başlıklı yazıya göz atabilirsiniz. Performans mühendisliği, debugging hikayeleri ve tweet boyutunu aşan alt seviye sistem çalışmaları hakkında daha fazla içerik Medium’da yayınlanıyor.
Yapay zeka özeti
UDP paket kayıplarının %30’unu network değil, alıcı sistemdeki buffer ve işleme hızındaki uyumsuzluk sebep olabilir. Detaylı debugging rehberi ve çözüm önerileri.