요약

  • 실리 윈도 신드롬(Silly Window Syndrome)은 첫 번째 작은 경계가 지나고 한참 뒤에도 작은 윈도 증가가 계속해서 작은 TCP 세그먼트를 만들어 내는 피드백 패턴이다.
  • TCP는 수신 측이 작은 윈도 업데이트를 지연하고 송신 측이 비효율적인 전송을 지연하도록 하여 이 패턴을 피하며, 재정의 타이머가 절제가 교착 상태로 변하는 것을 막는다.

거의 가득 찬 버퍼에서 수신 애플리케이션이 단 몇 바이트만 소비했다고 가정해 보자. 이제 수신 측 TCP에는 몇 바이트의 실제 여유 공간이 생긴다. 그 공간을 즉시 광고할 수도 있고, 송신 측은 그 공간을 채울 자격이 있다. 그 몇 바이트가 도착해 소비되면 다시 같은 크기의 공간이 생긴다. 완전히 유효한 윈도 업데이트가 완전히 유효한 작은 세그먼트를 만들고, 그 세그먼트의 진행은 다시 같은 크기의 업데이트를 부른다. 패킷 하나하나로는 아무것도 깨진 것이 없다. 문제는 그것들이 이루는 리듬이다.

데이비드 클라크(David Clark)의 RFC 813은 1982년에 그 리듬에 이름을 붙였다. 바로 실리 윈도 신드롬(SWS)이다. 이 메모는 SWS를 개별적인 작은 패킷으로 정의하지 않았다. 대신 긴 전송에서 스트림이 작은 조각들로 나뉘고 자연스럽게 다시 결합되지 못하는 안정적인 열화를 기술했다. 같은 유용한 데이터를 옮기기 위해 네트워크는 더 많은 헤더와 확인 응답을 실어 나르고, 호스트는 더 많은 프로토콜 작업을 수행하며, 손실과 재전송이 피해를 증폭시킬 수 있다. RFC 813은 세그먼트 평균 크기가 종단이 감당할 수 있는 크기의 10분의 1에 불과하고 재전송이 곱절로 늘어난 역사적 사례들을 보고했다. 이 관찰은 그 시대에 속하는 것이지 모든 현대 네트워크에 적용되는 것은 아니지만, 이 메커니즘을 단순한 미관상의 비효율로 치부할 수 없게 만들었다.

여기서 중요한 구분은 수신자가 제공하는 윈도와 송신자가 실제로 사용할 수 있는 윈도 사이의 차이다. 수신자가 1,000바이트를 광고하는 동안 950바이트가 아직 확인되지 않았다면, 송신자가 사용할 수 있는 바이트는 50바이트뿐이다. 그 50바이트를 보내고, 오른쪽 경계를 또 50바이트만큼 밀어 올리는 확인 응답을 받으면, 다음 사용 가능한 허용량도 다시 50바이트다. 자연스러운 경계—예를 들어 푸시된 단위의 끝—가 원래 효율적이던 할당을 쪼갤 수 있다. 그 이후로는 확인 응답과 윈도 산술이 그 조각을 계속 재현한다.

RFC 813의 수신 측 해법은 '가용한 모든 바이트를 즉시 광고해야 한다'고 전제할 때만 직관에 어긋난다. 애플리케이션이 적은 양의 공간을 확보한 뒤에도, 수신자는 광고되는 오른쪽 경계를 그대로 유지할 수 있다. 공간을 로컬에서는 기록하되 송신자에게는 공개하지 않는 것이다. 충분한 공간이 쌓이면 한 번의 유용한 점프로 윈도를 연다. 너무 오래 기다리면 파이프라인이 잠시 비어 시간을 잃을 수 있다. 너무 자주 열면 대역폭과 CPU를 소모하면서 처리량도 떨어뜨린다. 클라크는 구현이 절제 쪽으로 기울고, 다시 열 때마다 충분히 큰 세그먼트를 실을 수 있을 만큼 크게 열어야 한다고 주장했다.

RFC 1122는 이 교훈을 짝을 이루는 호스트 요구 사항으로 옮겼다. 4.2.3.3절은 수신 측 SWS 회피 알고리즘을 요구했다. 그 제안 규칙은 미광고 공간이 두 임계값 중 작은 쪽—수신 버퍼의 일정 비율 또는 유효 송신 MSS 하나—에 도달할 때까지RCV.NXT + RCV.WND를 고정하는 것이다. 권장 비율은 2분의 1이다. 현실적인 버퍼에서 실제 효과는 흔히 윈도를 바이트 단위가 아니라 대략 세그먼트 하나 분량씩 여는 것이다.

송신 측 역시 합법적이지만 비효율적인 초대를 거절해야 한다. RFC 1122 §4.2.3.4는 송신 측 SWS 회피 알고리즘을 요구했고, 다음 네 조건 중 하나가 충족되면 전송할 것을 권고했다. 전체 크기의 세그먼트가 맞을 때, 푸시된 데이터를 명시된 조건 아래 모두 보낼 수 있을 때, 최대 관측 윈도의 절반 이상을 사용할 수 있을 때, 또는 재정의 타이머가 만료될 때. 따라서 송신자는 작은 사용 가능 윈도를 즉시 행사해야 하는 지시가 아니라 신중하게 기다릴 수 있는 허가로 다룬다.

이 알고리즘에는 수신자가 직면하지 않는 불확실성이 하나 있다. 수신자는 자신의 버퍼 크기를 알지만 송신자는 모른다. 송신자는 연결에서 관측된 가장 큰 송신 윈도를 수신 용량의 추정치로 사용할 수 있지만, 수신자가 버퍼를 바꾸면 이 추정은 낡을 수 있다. 낡은 최댓값의 일정 비율을 영원히 기다리는 규칙은 교착 상태에 빠질 수 있다. 재정의 타이머가 그 탈출구다. 묶어 보내기가 효율을 높이지만, 언젠가는 송신자가 그 규칙에도 불구하고 전송한다. RFC 9293은 그 재정의 타이머에 대해 0.1~1.0초의 권장 범위를 유지하면서, 실제 구현 동작은 이 출처들이 입증하는 범위 밖에 둔다.

현대의 통합 TCP 명세는 양쪽 의무를 모두 보존한다. RFC 9293은 구현이 송신 측과 수신 측 모두에 SWS 회피를 포함해야 한다고 말한다. 또한 요약된 설명에서 흔히 흐려지는 구분도 유지한다. 네이글(Nagle) 알고리즘은 애플리케이션이 작은 증분으로 데이터를 공급할 때의 아주 작은 세그먼트를 억제한다. 송신 측 SWS 회피는 수신 윈도의 오른쪽 경계가 작은 증분으로 나아가서 생기는 아주 작은 세그먼트를 억제한다. 둘은 협력할 수 있지만 서로 다른 원인에 답한다.