← 기술 지식

기술 지식 / 컴퓨터 과학 / 네트워크 / 전송 계층

TCP 소량 쓰기 지연

앱 배치·TLS 레코드·Nagle·지연 ACK·NIC 전송을 분리하고 NODELAY의 지연 이득과 비용을 비교합니다.

네트워크 · 원리·구현·운영
기술 지식 트리

소량 쓰기 지연은 한 API 호출의 지연이 아니라 앱 프레임, TLS record, TCP 송신 큐, ACK, 상대 앱 처리라는 여러 경계의 합성 결과입니다. 따라서 옵션을 바꾸기 전에 같은 payload·RTT·연결 조건에서 각 경계의 시각을 기록해야 Nagle 문제와 단순한 앱 또는 TLS buffering을 구분할 수 있습니다.

send 호출 시각과 선로 전송 시각

앱이 헤더와 본문을 작은 두 쓰기로 보냈는데 상대 응답이 일정 시간 늦는다고 합시다. Nagle과 지연 ACK의 상호작용일 수 있지만, 앱의 flush·TLS 버퍼·이벤트 루프 정체도 비슷한 결과를 만들 수 있습니다. 먼저 어느 계층에 바이트가 머물렀는지 나누어야 합니다.

Nagle은 확인되지 않은 데이터가 남은 상황의 작은 쓰기를 모아 패킷 수를 줄이려는 정책이고, 지연 ACK는 수신 측이 ACK를 잠시 묶는 정책입니다. 두 정책은 목적과 실행 위치가 다릅니다.

첫 세그먼트와 다음 소량 쓰기 사이의 대기 상호작용

헤더가 먼저 작은 세그먼트로 나갔고 아직 ACK가 없습니다. Nagle 조건으로 다음 작은 본문이 기다리는데, 수신 앱은 본문까지 있어야 응답할 수 있고 수신 TCP는 ACK를 잠시 늦출 수 있습니다. 이 경우 추가 대기가 생길 수 있습니다.

시점 송신 측 수신 측
1 작은 헤더 송신 헤더 수신, 본문 필요
2 미확인 데이터가 있어 다음 작은 쓰기 대기 가능 ACK 묶음 대기 가능
3 ACK 수신 또는 다른 전송 조건 충족 ACK 전송
4 본문 송신 프레임 완성 후 앱 처리

이 표는 가능한 상호작용이지 모든 작은 메시지가 같은 ms만큼 지연된다는 프로토콜 보장이 아닙니다.

예를 들어 write(header)=t0, TLS flush=t1, 첫 segment 전송=t2, ACK=t3, 본문 전송=t4, 상대 앱 처리=t5를 기록하면 t1-t0는 앱/TLS 지연이고 두 번째 쓰기가 준비된 시각부터 ACK로 송신이 풀리는 시각까지가 Nagle·ACK 상호작용 후보입니다. ACK 이후의 t4-t3만으로 전체 대기를 설명할 수는 없습니다. TCP_NODELAY 후 t4가 당겨지지 않으면 원인은 다른 계층일 가능성이 큽니다. 반대로 지연이 줄면서 segment 수와 CPU가 증가하면 지연과 처리 비용 사이의 trade-off를 확인한 것입니다.

재현 실습은 헤더·본문 분할, 앱 단일 배치, NODELAY의 세 조건을 동일 연결 수와 메시지 간격으로 비교하는 것입니다. 예상 결과는 TCP 수신 경계가 앱 write 경계와 일치하지 않으며, 모든 조건에서 수신기는 length prefix 같은 프레이밍으로 부분 수신을 누적 처리해야 한다는 것입니다. MSS·ACK 패턴·OS 구현·다른 대기 조건이 영향을 줍니다.

한 메시지가 지나가는 여러 버퍼앱 프레임·flush. TLS 레코드·암호화. TCP 송신 큐: Nagle · 창 · pacing. NIC·실제 경로: offload · 세그먼트 전송write 호출암호화 바이트송신 가능 시점앱 프레임·flushTLS 레코드·암호화TCP 송신 큐Nagle · 창 · pacingNIC·실제 경로offload · 세그먼트 전송
한 메시지가 지나가는 여러 버퍼 화살표는 바이트의 전달 경로입니다. 각 단계의 경계는 일대일이 아니며 한 앱 write가 한 TLS record·TCP segment가 된다고 가정하지 않습니다.
그림을 글로 읽기
  • 앱 프레임·flush
  • TLS 레코드·암호화
  • TCP 송신 큐: Nagle · 창 · pacing
  • NIC·실제 경로: offload · 세그먼트 전송
  1. 앱 프레임·flush → TLS 레코드·암호화: write 호출
  2. TLS 레코드·암호화 → TCP 송신 큐: 암호화 바이트
  3. TCP 송신 큐 → NIC·실제 경로: 송신 가능 시점

원래 쓰기·앱 배치·TCP_NODELAY의 동일 부하 비교

첫째, 헤더·본문을 따로 쓰는 원래 코드를 측정합니다. 둘째, 앱에서 완성 프레임을 모아 한 번에 쓰되 최대 배치 대기 시간을 제한합니다. 셋째, TCP_NODELAY를 적용해 Nagle의 대기를 제거한 조건을 비교합니다.

NODELAY는 앱·TLS·프록시의 버퍼링을 끄거나 혼잡 창을 늘리지 않습니다. 개선이 없다면 다른 계층을 살펴야 합니다. 지연이 줄어도 작은 패킷 수·CPU·대역폭·인터럽트 부담이 늘 수 있으므로 모든 연결에 무조건 켜지 않습니다. 지연 민감 입력과 대량 배치 전송의 요구는 다릅니다.

TCP 스트림 프레이밍과 송신 완료 의미

한 번에 프레임을 보내거나 NODELAY를 켜도 TCP는 바이트 스트림입니다. 상대는 부분 수신·여러 프레임 합쳐 수신을 계속 처리해야 합니다. TLS record 경계도 앱 메시지 경계를 대신하지 않습니다.

로컬 송신 완료는 상대 앱의 파싱·DB 커밋 확인이 아닙니다. 중요한 변경에는 요청 ID·앱 응답·결과 조회가 필요합니다. 작은 쓰기를 묶는 최적화가 재시도와 중복 처리 계약을 바꾸지 않도록 합니다.

계층별 캡처 지점과 전송 시각

앱의 프레임 완성, write 호출, TLS flush, 커널 큐, 패킷 관찰, 상대 ACK·앱 처리 시각을 구분합니다. NIC offload로 호스트 캡처에 큰 묶음이 보이거나 수신이 합쳐 보일 수 있어 캡처 한 장만으로 실제 선로 세그먼트를 단정하지 않습니다.

같은 payload·연결 수·RTT에서 p95·p99·패킷 수·재전송·CPU를 비교합니다. 특정 메시지 크기·간격에서만 튀는지, 앱 호출 자체가 늦는지 확인해야 어느 옵션이 실제 원인을 줄였는지 설명할 수 있습니다.

후속·관련 개념

함께 읽을 문서

전체 기술 지식
선택 연습 · 관련 질문 2개

질문은 이해를 확인하는 보조 자료입니다. 학습 경로와 문서의 범위는 질문 수와 독립적입니다.