GN⁺ 5달전 | parent | ★ favorite | on: 항상 문제는 TCP_NODELAY다(brooker.co.za)
Hacker News 의견들
  • 예전 멀티포인트 네트워킹 시절에 만들어진 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로 설정 시 처리량이 크게 향상됨
    • 어떤 게임을 개발 중인지 궁금함. 나도 EbitengineGolang으로 게임 개발을 즐기고 있어서 관심이 많음
  • Nagle 본인이 10년 전쯤 말하길, 진짜 문제는 delayed ACK라고 함
    관련 링크 참고
    요즘 워크로드에서는 delayed ACK이 큰 이점을 주지 않는다고 생각함
    HTTP 중심의 현대 환경에서는 Nagle과 delayed ACK 둘 다 끄는 게 낫다고 봄
    • 원문에서도 이를 다룸
      데이터센터 간 RTT가 수백 마이크로초 수준이라, 한 RTT라도 지연시키는 건 오히려 손해일 수 있음
  • 폴란드어로 “nagle”은 “갑자기”라는 뜻인데, 알고리즘 이름과 너무 잘 어울려서 놀라웠음
    • Nominative determinism의 또 다른 사례 같음
      위키 링크
    • 흥미롭게도 “NODELAY on”일 때는 갑자기 보내고, “off”일 때는 한꺼번에 보내는 식으로 단어 의미가 양쪽 설정을 모두 담고 있는 듯함
    • 실제로는 John Nagle이라는 사람이 작성한 RFC 896에 기반한 알고리즘임
  • 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도 비슷한 문제를 겪음
    • TCP_CORK가 뭔지 궁금함
  • (2024) 이전 토론은 이 링크에서 있었음
  • Oxide and Friends 팟캐스트 에피소드에서 이 주제를 다룸
    꽤 흥미로운 내용임
    • Oxide는 서버 OS와 하드웨어를 새로 설계하는 회사라, 전통적인 프로토콜을 재검토하는 접근이 브랜드 철학과 잘 맞음
  • Nagle 알고리즘은 정책을 커널에 넣은 것 같아 어색함
    애플리케이션이 지연과 처리량의 균형을 직접 조절할 수 있어야 함
    • delayed ack이 없을 때는 합리적인 알고리즘이며, TCP 스택의 일부로 존재하는 이유는 그 계층에서 문제를 해결하려 했기 때문임
      하지만 애플리케이션 수준에서 구현하려면 unacked data를 알아야 해서 비효율적임
    • 이론적으로는 맞지만, 현실적으로는 대부분의 유저스페이스 코드가 네트워크 하부를 신경 쓰지 않음
      단순한 20ms flush 타이머만 있었어도 훨씬 나았을 것임
    • 사실 TCP_NODELAY는 소켓 단위로 설정되므로, 애플리케이션이 직접 선택하는 유저스페이스 결정에 가깝다고 봄
    • 한 프로그램의 트레이드오프가 다른 프로그램에 영향을 줄 수 있으므로, 커널이 전체 시스템 관점에서 중재자 역할을 하는 게 필요하다고 생각함