예전 멀티포인트 네트워킹 시절에 만들어진 Nagle 알고리즘의 배경을 설명함
당시 여러 호스트가 하나의 이더넷 채널을 공유했기 때문에 충돌을 피하기 위해 CSMA/CD를 사용했음
하지만 오늘날 대부분의 이더넷은 포인트 투 포인트 구조로, 송수신이 동시에 가능한 풀 듀플렉스 환경임
따라서 CSMA는 더 이상 필요하지 않으며, TCP_NODELAY를 설정해 Nagle 알고리즘을 비활성화하는 것이 대부분의 경우 합리적이라 생각함
CSMA 관련 동기가 Nagle 알고리즘 설계에 실제로 있었던 건지, 아니면 단순히 시대적 배경을 언급한 것인지 궁금함
사실 Nagle 알고리즘은 단순히 패킷 병합(coalescing) 목적이었음
기본값으로 설정된 것은 네트워킹 역사상 큰 실수 중 하나라고 생각함
참고로 이더넷은 CSMA/CD, WiFi는 CSMA/CA를 사용함
2014년쯤 데이터센터 스위치를 교체할 때, 10Mbit 하프 듀플렉스를 지원하지 않아 일부 구형 장비를 유지해야 했던 경험이 있음
애플리케이션이 패킷 크기를 신경 쓰지 않거나 지연에 민감하지 않을 때는 Nagle이 꽤 합리적임
너무 작은 패킷 생성을 방지해줌
네트워크 레이어 혼동이 있는 것 같음
Nagle은 TCP 계층의 최적화로, 작은 패킷을 묶어 효율을 높이는 역할임
CSMA는 물리/데이터링크 계층의 문제로, Nagle과는 별개임
게임 개발 중 네트워크 지연 문제를 디버깅하다가 이 글을 발견했음
Go로 작성된 백엔드는 기본적으로 TCP_NODELAY가 설정되어 있어서 원인은 아니었지만, Nagle의 문제 인식에 대한 부분이 흥미로웠음
예전 토론도 있었는데 이 스레드 참고 가능함
Julia Evans의 좋은 글도 추천함
DICOM 프로토콜처럼 채팅형 통신에서는 TCP_NODELAY=1로 설정 시 처리량이 크게 향상됨
어떤 게임을 개발 중인지 궁금함. 나도 Ebitengine과 Golang으로 게임 개발을 즐기고 있어서 관심이 많음
Nagle 본인이 10년 전쯤 말하길, 진짜 문제는 delayed ACK라고 함 관련 링크 참고
요즘 워크로드에서는 delayed ACK이 큰 이점을 주지 않는다고 생각함
HTTP 중심의 현대 환경에서는 Nagle과 delayed ACK 둘 다 끄는 게 낫다고 봄
원문에서도 이를 다룸
데이터센터 간 RTT가 수백 마이크로초 수준이라, 한 RTT라도 지연시키는 건 오히려 손해일 수 있음
폴란드어로 “nagle”은 “갑자기”라는 뜻인데, 알고리즘 이름과 너무 잘 어울려서 놀라웠음
Nagle 알고리즘이 커널 기본값으로 설정된 건 이상하다고 생각함
언제 보낼지, 언제 버퍼링할지는 애플리케이션이 결정해야 함
글에서 MSG_MORE를 언급하지 않은 게 의외였음
Linux에서는 추가 데이터가 곧 전송될 것임을 커널에 알려주는 힌트로, 헤더와 데이터를 따로 보낼 때 유용함 io_uring과 함께 쓰면 더 효율적임
사실 하나의 시스템 콜로 여러 조각 데이터를 복사 없이 보낼 수도 있음
Nagle 알고리즘의 문제는 소켓 API에 즉시 전송(flush) 기능이 없다는 점이라 생각함
즉시 응답이 필요한 메시지 이후에 버퍼를 비워 보내는 기능이 있으면 좋겠음
요즘 TCP 채널은 동기·비동기 메시지가 섞여 있어서 더 복잡함 SCTP 같은 프로토콜이 더 널리 쓰였으면 함
스트림 API에 flush 기능이 없다는 점에 동의함. 명백한 설계 누락이라 생각함
네트워크 I/O를 파일처럼 다루려는 UNIX 철학은 이해하지만, 메시지 지향 API가 처음부터 있었으면 이런 문제는 없었을 것임
TLS 같은 래핑에서도 메시지 경계를 찾는 게 번거로움
모든 send에 MSG_MORE를 붙이고 마지막에만 빼면 간접적으로 flush 효과를 낼 수 있을 듯함
스트림 API는 여러모로 불편함
이상적으로는 “버퍼링 허용” 비트를 설정해 큰 전송을 나누고 마지막에 “즉시 전송”을 지정할 수 있어야 함 TCP_CORK는 그나마 비슷한 대안이지만 좀 조잡함
파일 I/O도 비슷한 문제를 겪음
Hacker News 의견들
당시 여러 호스트가 하나의 이더넷 채널을 공유했기 때문에 충돌을 피하기 위해 CSMA/CD를 사용했음
하지만 오늘날 대부분의 이더넷은 포인트 투 포인트 구조로, 송수신이 동시에 가능한 풀 듀플렉스 환경임
따라서 CSMA는 더 이상 필요하지 않으며, TCP_NODELAY를 설정해 Nagle 알고리즘을 비활성화하는 것이 대부분의 경우 합리적이라 생각함
기본값으로 설정된 것은 네트워킹 역사상 큰 실수 중 하나라고 생각함
2014년쯤 데이터센터 스위치를 교체할 때, 10Mbit 하프 듀플렉스를 지원하지 않아 일부 구형 장비를 유지해야 했던 경험이 있음
너무 작은 패킷 생성을 방지해줌
Nagle은 TCP 계층의 최적화로, 작은 패킷을 묶어 효율을 높이는 역할임
CSMA는 물리/데이터링크 계층의 문제로, Nagle과는 별개임
Go로 작성된 백엔드는 기본적으로 TCP_NODELAY가 설정되어 있어서 원인은 아니었지만, Nagle의 문제 인식에 대한 부분이 흥미로웠음
예전 토론도 있었는데 이 스레드 참고 가능함
DICOM 프로토콜처럼 채팅형 통신에서는 TCP_NODELAY=1로 설정 시 처리량이 크게 향상됨
관련 링크 참고
요즘 워크로드에서는 delayed ACK이 큰 이점을 주지 않는다고 생각함
HTTP 중심의 현대 환경에서는 Nagle과 delayed ACK 둘 다 끄는 게 낫다고 봄
데이터센터 간 RTT가 수백 마이크로초 수준이라, 한 RTT라도 지연시키는 건 오히려 손해일 수 있음
위키 링크
언제 보낼지, 언제 버퍼링할지는 애플리케이션이 결정해야 함
Linux에서는 추가 데이터가 곧 전송될 것임을 커널에 알려주는 힌트로, 헤더와 데이터를 따로 보낼 때 유용함
io_uring과 함께 쓰면 더 효율적임
즉시 응답이 필요한 메시지 이후에 버퍼를 비워 보내는 기능이 있으면 좋겠음
요즘 TCP 채널은 동기·비동기 메시지가 섞여 있어서 더 복잡함
SCTP 같은 프로토콜이 더 널리 쓰였으면 함
TLS 같은 래핑에서도 메시지 경계를 찾는 게 번거로움
이상적으로는 “버퍼링 허용” 비트를 설정해 큰 전송을 나누고 마지막에 “즉시 전송”을 지정할 수 있어야 함
TCP_CORK는 그나마 비슷한 대안이지만 좀 조잡함
파일 I/O도 비슷한 문제를 겪음
꽤 흥미로운 내용임
애플리케이션이 지연과 처리량의 균형을 직접 조절할 수 있어야 함
하지만 애플리케이션 수준에서 구현하려면 unacked data를 알아야 해서 비효율적임
단순한 20ms flush 타이머만 있었어도 훨씬 나았을 것임