18 puan yazan GN⁺ 2025-12-23 | 1 yorum | WhatsApp'ta paylaş
  • Dağıtık sistemlerde gecikme (latency) sorunlarını debug ederken ilk kontrol edilmesi gereken ayarın TCP_NODELAY olduğu belirtiliyor
  • Nagle algoritması, 1984 tarihli RFC896’da önerilen bir yöntem olup, küçük paketlerin iletiminde TCP başlık ek yükünü azaltmak için tasarlanmıştı
  • Ancak delayed ACK (gecikmeli ACK) mekanizmasıyla birleştiğinde, veri iletimi ACK alınana kadar gecikir ve gecikmeye duyarlı uygulamaların performansını kötüleştirir
  • Modern veri merkezi ortamlarında RTT çok kısadır ve sistemlerin çoğu zaten büyük mesajlar gönderdiğinden Nagle algoritmasının faydası neredeyse ortadan kalkmıştır
  • Bu nedenle modern dağıtık sistemlerde TCP_NODELAY varsayılan olarak etkin olmalıdır ve Nagle algoritmasına artık ihtiyaç yoktur

Nagle algoritmasının arka planı

  • 1984’te John Nagle’ın RFC896 belgesi, klavye girişi gibi küçük veri iletimlerinde ortaya çıkan 40 baytlık başlığa karşı 1 bayt verinin %4000 ek yük sorununu çözmek için önerildi
    • O dönemde sorun, kullanıcı her tuşa bastığında küçük paketlerin gönderilmesi ve bunun ağ verimliliğini düşürmesiydi
    • Çözüm, önceki veri ACK almamışken yeni bir segmentin gönderilmesini engellemekti
  • Bu yaklaşım o dönemki ağ koşullarında etkiliydi, ancak gecikmenin (latency) önemli olduğu modern sistemler için uygun değil

Nagle algoritması ile Delayed ACK etkileşimi

  • Delayed ACK (RFC813, RFC1122), alıcının ACK’yi hemen göndermeyip, yanıt verisi oluşana ya da zamanlayıcı dolana kadar ACK’yi geciktirdiği bir mekanizmadır
  • Nagle algoritması ACK beklerken iletimi durdurur, delayed ACK de ACK’yi geciktirir; böylece iki tarafın da birbirini beklediği bir kilitlenme durumu oluşur
  • John Nagle da bu kombinasyonu “korkunç bir kombinasyon” olarak tanımlamış, iki özelliğin bağımsız olarak geliştirildiğini ama birlikte kullanıldıklarında gecikmeye yol açtıklarını belirtmiştir

Modern ortamdaki sorunlar

  • Veri merkezinde RTT yaklaşık 500μs düzeyindedir; aynı bölgede bile birkaç milisaniye gibi oldukça kısa süreler görülür
  • Böyle bir ortamda iletimi bir RTT kadar geciktirmek performans kaybına neden olur
  • Ayrıca modern dağıtık sistemler TLS, serileştirme, protokol ek yükü gibi nedenlerle zaten yeterince büyük mesajlar gönderdiğinden, tek baytlık paket sorunu neredeyse hiç kalmamıştır
  • Küçük mesaj optimizasyonu artık uygulama katmanında ele alınmaktadır

TCP_NODELAY neden gerekli?

  • Gecikmeye duyarlı dağıtık sistemlerde Nagle algoritmasını devre dışı bırakmak için TCP_NODELAY’in etkinleştirilmesi önerilir
    • Bu, “verimsiz” ya da “yanlış bir ayar” değil; modern donanım ve trafik özelliklerine uygun bir tercihtir
  • Yazar, TCP_NODELAY’in varsayılan olması gerektiğini savunuyor
    • Bazı, “her write() çağrısında gönderim yapan” kodlar yavaşlayabilir; ancak bu tür kodların zaten kökten düzeltilmesi gerekir

Diğer ilgili seçenekler

  • TCP_QUICKACK seçeneği ACK gecikmesini azaltır, ancak taşınabilirlik sorunları ve tutarsız davranışı nedeniyle temel çözüm değildir
  • Esas sorun, çekirdeğin veriyi uygulamanın amaçladığından daha uzun süre elinde tutmasıdır; veri write() çağrısı yapıldığında hemen gönderilmelidir

Sonuç

  • Nagle algoritması geçmişte ağ verimliliğini artırmak için harika bir buluştu, ancak
    modern yüksek hızlı ağlar ve dağıtık sistem ortamlarında artık gecikmeye neden olan eski bir özellik haline gelmiştir
  • Bu yüzden TCP_NODELAY’i her zaman etkinleştirmek, modern sistem tasarımının temel ilkesi olarak sunuluyor

1 yorum

 
GN⁺ 2025-12-23
Hacker News yorumları
  • Eski çok noktalı ağ iletişimi döneminde ortaya çıkan Nagle algoritmasının arka planını açıklıyor
    O dönemde birden fazla host tek bir Ethernet kanalını paylaştığı için çakışmaları önlemek amacıyla CSMA/CD kullanılıyordu
    Ancak bugün çoğu Ethernet, noktadan noktaya yapıda ve gönderme ile almanın aynı anda mümkün olduğu full duplex bir ortamda çalışıyor
    Bu nedenle CSMA artık gerekli değil ve çoğu durumda Nagle algoritmasını devre dışı bırakmak için TCP_NODELAY ayarlamanın mantıklı olduğunu düşünüyor
    • CSMA ile ilgili motivasyonun gerçekten Nagle algoritmasının tasarımında yer alıp almadığını, yoksa sadece dönemin bağlamından mı bahsedildiğini merak ediyorum
    • Aslında Nagle algoritması sadece paket birleştirme (coalescing) amacı taşıyordu
      Varsayılan olarak etkin gelmesi, ağ iletişimi tarihindeki büyük hatalardan biri gibi görünüyor
    • Bilgi olsun diye, Ethernet CSMA/CD, WiFi ise CSMA/CA kullanır
      2014 civarında veri merkezi switch'lerini değiştirirken 10Mbit half duplex desteklemediği için bazı eski cihazları elde tutmak zorunda kaldığım bir deneyim yaşamıştım
    • Uygulama paket boyutlarını umursamıyorsa ya da gecikmeye duyarlı değilse Nagle oldukça makul
      Aşırı küçük paketlerin oluşmasını engelliyor
    • Burada bir katman karışıklığı var gibi görünüyor
      Nagle, verimliliği artırmak için küçük paketleri bir araya getiren TCP katmanı optimizasyonudur
      CSMA ise fiziksel/veri bağlantı katmanı problemidir; Nagle ile ayrı şeylerdir
  • Oyun geliştirirken ağ gecikmesi sorununu debug ederken bu yazıya rastladım
    Go ile yazılmış backend'de varsayılan olarak TCP_NODELAY açık olduğundan sebep bu değildi, ama Nagle'ın problem olarak algılanmasına dair kısım ilgimi çekti
    Daha önce de bir tartışma vardı; bu başlığa bakılabilir
    • Julia Evans'ın güzel yazısını da öneririm
      DICOM protokolü gibi sohbet tarzı iletişimde, TCP_NODELAY=1 ayarlanınca aktarım hızı ciddi biçimde artıyor
    • Hangi oyunu geliştirdiğini merak ettim. Ben de Ebitengine ve Golang ile oyun geliştirmeyi seviyorum, o yüzden ilgimi çekti
  • Nagle'ın kendisi yaklaşık 10 yıl önce asıl sorunun delayed ACK olduğunu söylemişti
    İlgili bağlantıya bakılabilir
    Günümüz iş yüklerinde delayed ACK'in büyük bir fayda sağladığını düşünmüyorum
    HTTP merkezli modern ortamda hem Nagle'ı hem de delayed ACK'i kapatmanın daha iyi olduğunu düşünüyorum
    • Yazının kendisi de buna değiniyor
      Veri merkezleri arası RTT yüzlerce mikrosaniye düzeyinde olduğundan, tek bir RTT kadar bile geciktirmek ters etki yaratabilir
  • Lehçede “nagle” kelimesi “aniden” anlamına geliyor; algoritmanın adıyla bu kadar iyi uyuşmasına şaşırdım
    • Bunun Nominative determinism için bir başka örnek gibi durduğunu söyleyebiliriz
      Wiki bağlantısı
    • İlginç olan şu ki “NODELAY on” iken aniden gönderiyor, “off” iken topluca gönderiyor; sanki kelimenin anlamı her iki ayarı da kapsıyor gibi
    • Aslında bu, RFC 896 yazarı John Nagle adlı kişiye dayanan bir algoritma
  • Nagle algoritmasının çekirdek varsayılanı olarak gelmesi bana garip geliyor
    Ne zaman gönderileceğine ve ne zaman tamponlanacağına uygulama karar vermeli
  • Yazıda MSG_MORE'dan bahsedilmemesi şaşırtıcıydı
    Linux'ta bu, yakında ek veri gönderileceğini çekirdeğe bildiren bir ipucu ve header ile veriyi ayrı ayrı gönderirken kullanışlı
    io_uring ile birlikte kullanıldığında daha da verimli
    • Hatta tek bir sistem çağrısıyla birden fazla veri parçasını kopyasız göndermek de mümkün
  • Bence Nagle algoritmasının asıl sorunu, socket API'sinde anında gönderme (flush) özelliğinin olmaması
    Anında yanıt gerektiren bir mesajdan sonra tamponu boşaltıp gönderme imkânı olsa iyi olurdu
    Günümüz TCP kanallarında senkron ve asenkron mesajlar iç içe geçtiği için durum daha da karmaşık
    SCTP gibi protokollerin daha yaygın kullanılmasını isterdim
    • Stream API'de flush olmamasına katılıyorum. Bu bariz bir tasarım eksikliği gibi duruyor
    • Ağ G/Ç'sini dosya gibi ele alma yönündeki UNIX felsefesi anlaşılır, ama baştan mesaj odaklı bir API olsaydı bu sorunlar ortaya çıkmazdı
      TLS gibi sarmalamalarda da mesaj sınırlarını bulmak zahmetli oluyor
    • Her send çağrısına MSG_MORE ekleyip sadece sonuncusunda çıkarmak, dolaylı olarak flush etkisi yaratabilir gibi görünüyor
    • Stream API birçok açıdan rahatsız edici
      İdeal olarak “tamponlamaya izin ver” bitiyle büyük bir gönderimi bölüp sonda “hemen gönder” işareti vermek mümkün olmalı
      TCP_CORK buna en yakın alternatiflerden biri ama biraz kaba bir çözüm
      Dosya G/Ç'si de benzer bir sorun yaşıyor
    • TCP_CORK'un ne olduğunu merak ettim
  • (2024) Önceki tartışma bu bağlantıdaydı
  • Oxide and Friends podcast bölümü bu konuyu ele alıyor
    Oldukça ilginç içerik var
    • Oxide, sunucu işletim sistemi ve donanımı yeniden tasarlayan bir şirket; bu yüzden geleneksel protokolleri yeniden değerlendiren yaklaşım markanın felsefesiyle oldukça uyumlu
  • Nagle algoritması politikayı çekirdeğe koymak gibi geldiği için tuhaf duruyor
    Uygulamanın gecikme ile throughput arasındaki dengeyi doğrudan ayarlayabilmesi gerekir
    • delayed ACK olmadığında makul bir algoritma ve TCP yığınının parçası olarak var olmasının sebebi de sorunu o katmanda çözmeye çalışmaları
      Ama uygulama seviyesinde bunu yapmak için unacked data durumunu bilmek gerekir, bu da verimsiz olur
    • Teoride doğru, ama pratikte kullanıcı alanındaki kodların çoğu ağın alt katmanlarıyla ilgilenmiyor
      Basit bir 20ms flush zamanlayıcısı bile çok daha iyi olurdu
    • Aslında TCP_NODELAY socket bazında ayarlandığı için, bunu uygulamanın doğrudan yaptığı bir user-space kararı olarak görmek de mümkün
    • Bir programın tercihleri başka bir programı etkileyebileceği için, çekirdeğin tüm sistem açısından arabulucu rolü üstlenmesi gerektiğini düşünüyorum