हमेशा समस्या TCP_NODELAY ही होती है
(brooker.co.za)- वितरित सिस्टम में latency समस्या को डिबग करते समय सबसे पहले TCP_NODELAY सेटिंग की जांच करनी चाहिए
- Nagle algorithm 1984 के RFC896 में प्रस्तावित एक तरीका है, जिसे छोटे packets भेजते समय TCP header overhead कम करने के लिए डिज़ाइन किया गया था
- लेकिन जब यह delayed ACK मेकेनिज़्म के साथ जुड़ता है, तो ACK मिलने तक डेटा ट्रांसमिशन रुक जाता है और latency-sensitive applications का प्रदर्शन खराब हो जाता है
- आधुनिक data center वातावरण में RTT बहुत कम होता है, और ज़्यादातर सिस्टम पहले से ही बड़े messages भेजते हैं, इसलिए Nagle algorithm के फायदे लगभग समाप्त हो चुके हैं
- इसलिए आधुनिक वितरित सिस्टम में TCP_NODELAY को डिफ़ॉल्ट रूप से सक्षम करना चाहिए, और Nagle algorithm अब व्यावहारिक रूप से ज़रूरी नहीं है
Nagle algorithm की पृष्ठभूमि
- 1984 में John Nagle के RFC896 ने keyboard input जैसे छोटे डेटा ट्रांसफर में होने वाली 40-byte header बनाम 1-byte data के 4000% overhead की समस्या को हल करने के लिए यह तरीका प्रस्तावित किया था
- उस समय समस्या यह थी कि उपयोगकर्ता हर अक्षर टाइप करते ही छोटे packets भेजे जाते थे, जिससे network efficiency कम हो जाती थी
- इसका समाधान यह था कि जब तक पिछला डेटा ACK न हो जाए, तब तक नया segment न भेजा जाए
- यह तरीका उस समय के network environment में प्रभावी था, लेकिन latency महत्वपूर्ण होने वाले आधुनिक सिस्टम के लिए उपयुक्त नहीं है
Nagle algorithm और Delayed ACK की परस्पर क्रिया
- Delayed ACK (RFC813, RFC1122) एक तरीका है जिसमें receiving side तुरंत ACK नहीं भेजती, बल्कि response data आने या timer expire होने तक ACK को रोककर रखती है
- Nagle algorithm ACK का इंतज़ार करते हुए ट्रांसमिशन रोक देता है, और delayed ACK ACK भेजने में देर करता है, इसलिए दोनों तरफ़ एक-दूसरे का इंतज़ार करने वाली deadlock जैसी स्थिति बन जाती है
- John Nagle ने ख़ुद इस संयोजन को “भयानक संयोजन” कहा था, और बताया कि दोनों फीचर अलग-अलग लाए गए थे, लेकिन साथ उपयोग होने पर latency पैदा करते हैं
आधुनिक वातावरण में समस्याएँ
- data center के भीतर RTT लगभग 500μs होता है, और एक ही region के भीतर भी यह कुछ milliseconds के स्तर पर बहुत कम होता है
- ऐसे वातावरण में एक RTT जितनी देरी भी प्रदर्शन हानि में बदल जाती है
- इसके अलावा आधुनिक वितरित सिस्टम TLS, serialization, protocol overhead आदि के कारण पहले से ही काफ़ी बड़े messages भेजते हैं, इसलिए single-byte packet की समस्या लगभग नहीं के बराबर रह गई है
- छोटे messages की optimization अब application layer में की जाती है
TCP_NODELAY की आवश्यकता
- latency-sensitive distributed systems में Nagle algorithm को बंद करने के लिए TCP_NODELAY सक्षम करना अनुशंसित है
- यह कोई “inefficient” या “गलत configuration” नहीं है, बल्कि आधुनिक hardware और traffic characteristics के अनुरूप चुनाव है
- लेखक का तर्क है कि TCP_NODELAY ही default होना चाहिए
- कुछ ऐसा code जो हर
write()call पर तुरंत भेजता है, धीमा पड़ सकता है, लेकिन ऐसे code को मूल रूप से सुधारा जाना चाहिए
- कुछ ऐसा code जो हर
अन्य संबंधित विकल्प
- TCP_QUICKACK विकल्प ACK delay कम करता है, लेकिन portability issues और असंगत व्यवहार के कारण यह मूल समाधान नहीं है
- असली समस्या यह है कि kernel डेटा को application के इच्छित समय से ज़्यादा देर तक रोके रखता है, जबकि
write()call पर उसे तुरंत भेजा जाना चाहिए
निष्कर्ष
- Nagle algorithm अतीत में network efficiency बढ़ाने के लिए एक शानदार आविष्कार था, लेकिन
आधुनिक high-speed networks और distributed systems के माहौल में यह उल्टा latency बढ़ाने वाला पुराना फीचर बन गया है - इसलिए TCP_NODELAY को हमेशा सक्षम रखना आधुनिक सिस्टम डिज़ाइन का बुनियादी सिद्धांत माना जाना चाहिए
1 टिप्पणियां
Hacker News की राय
उस समय कई hosts एक ही Ethernet channel साझा करते थे, इसलिए collisions से बचने के लिए CSMA/CD का उपयोग होता था
लेकिन आज अधिकांश Ethernet point-to-point संरचना वाले हैं, और full duplex वातावरण में काम करते हैं जहाँ भेजना और पाना एक साथ संभव है
इसलिए CSMA अब ज़रूरी नहीं है, और TCP_NODELAY सेट करके Nagle algorithm को निष्क्रिय करना ज़्यादातर मामलों में उचित लगता है
इसे default बनाना networking इतिहास की बड़ी गलतियों में से एक लगता है
लगभग 2014 में data center switches बदलते समय, 10Mbit half duplex को समर्थन न मिलने के कारण कुछ पुराने उपकरण बनाए रखने पड़े थे
यह बहुत छोटे packets बनने से रोकता है
Nagle TCP layer का optimization है, जिसका काम छोटे packets को जोड़कर efficiency बढ़ाना है
CSMA physical/data link layer की समस्या है, और Nagle से अलग है
Go में लिखा backend वैसे भी default रूप से TCP_NODELAY सेट करता है, इसलिए कारण यह नहीं था, लेकिन Nagle की समस्या-समझ पर चर्चा दिलचस्प लगी
पहले की चर्चा भी थी, यह thread देख सकते हैं
DICOM protocol जैसी chatty communication में TCP_NODELAY=1 सेट करने पर throughput काफ़ी बढ़ जाता है
संबंधित लिंक देखें
मेरा मानना है कि आज के workloads में delayed ACK कोई बड़ा लाभ नहीं देता
HTTP-केंद्रित आधुनिक वातावरण में Nagle और delayed ACK दोनों को बंद करना बेहतर लगता है
data centers के बीच RTT सैकड़ों microseconds के स्तर का होता है, इसलिए एक RTT जितनी भी देरी करना उल्टा नुकसानदेह हो सकता है
wiki link
कब भेजना है और कब buffer करना है, यह application को तय करना चाहिए
Linux में यह kernel को संकेत देता है कि और data जल्द आने वाला है, इसलिए header और data को अलग-अलग भेजते समय उपयोगी है
io_uring के साथ इसका उपयोग और अधिक efficient है
अगर ऐसे messages के बाद buffer खाली कर भेजने की सुविधा हो जिनमें तुरंत response चाहिए, तो अच्छा होगा
आजकल TCP channels में synchronous और asynchronous messages मिले-जुले होते हैं, इसलिए बात और जटिल हो जाती है
काश SCTP जैसे protocols ज़्यादा व्यापक रूप से उपयोग में आते
TLS जैसी wrapping में भी message boundaries ढूँढना झंझट भरा होता है
आदर्श रूप से “buffering allowed” bit सेट करके बड़े transfer को टुकड़ों में बाँटना चाहिए और अंत में “send immediately” निर्दिष्ट कर पाना चाहिए
TCP_CORK कुछ हद तक मिलती-जुलती वैकल्पिक व्यवस्था है, लेकिन थोड़ी भद्दी है
file I/O भी ऐसी ही समस्या झेलता है
काफ़ी दिलचस्प सामग्री है
application को latency और throughput के बीच संतुलन खुद नियंत्रित कर पाना चाहिए
लेकिन इसे application स्तर पर लागू करने के लिए unacked data जानना पड़ेगा, जो inefficient है
सिर्फ एक साधारण 20ms flush timer भी होता तो बहुत बेहतर होता