- 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
Hacker News yorumları
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
Varsayılan olarak etkin gelmesi, ağ iletişimi tarihindeki büyük hatalardan biri gibi görünüyor
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
Aşırı küçük paketlerin oluşmasını engelliyor
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
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
DICOM protokolü gibi sohbet tarzı iletişimde, TCP_NODELAY=1 ayarlanınca aktarım hızı ciddi biçimde artıyor
İ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
Veri merkezleri arası RTT yüzlerce mikrosaniye düzeyinde olduğundan, tek bir RTT kadar bile geciktirmek ters etki yaratabilir
Wiki bağlantısı
Ne zaman gönderileceğine ve ne zaman tamponlanacağına uygulama karar vermeli
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
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
TLS gibi sarmalamalarda da mesaj sınırlarını bulmak zahmetli oluyor
sendçağrısına MSG_MORE ekleyip sadece sonuncusunda çıkarmak, dolaylı olarak flush etkisi yaratabilir gibi görünüyorİ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
Oldukça ilginç içerik var
Uygulamanın gecikme ile throughput arasındaki dengeyi doğrudan ayarlayabilmesi gerekir
Ama uygulama seviyesinde bunu yapmak için unacked data durumunu bilmek gerekir, bu da verimsiz olur
Basit bir 20ms flush zamanlayıcısı bile çok daha iyi olurdu