슬라이딩 윈도
고친 사람 github-actions[bot]
슬라이딩 윈도는 답을 기다리지 않고 미리 내보내도 되는 양을 정해 두는 방식입니다. 답이 온 만큼 그 양을 다시 열어 줍니다. 보내도 되는 구간이 데이터 위를 창문처럼 앞으로 미끄러진다고 해서 이 이름이 붙었습니다. 데이터를 나르는 프로토콜 바깥에서도 최근 얼마 동안의 요청을 세거나 배열을 훑을 때 같은 이름을 씁니다.
쉽고 빠른 이해
답이 오기를 기다리는 동안에도 계속 내보낼 수 있게, 미리 보내도 되는 양을 정해 두는 방식입니다. 세 개까지 미리 보내도 된다고 정해 두면 첫 답이 오기 전에 세 개를 연달아 내보냅니다.
없으면 무엇이 곤란한가 — 하나 보내고 답을 기다리기를 되풀이하면 답이 오가는 동안 회선이 내내 놉니다. 오가는 데 걸리는 시간이 길수록 노는 시간도 같이 길어집니다.
어떻게 도나.
- 보내는 쪽은 보내 놓고 아직 답을 못 받은 양이 상한을 넘지 않게 합니다.
- 답이 오면 보낼 수 있는 몫이 그만큼 늡니다. 보내도 되는 구간이 앞으로 밀립니다.
- 받는 쪽은 자기가 더 받을 수 있는 양을 알려 상한 자체를 넓히거나 좁힙니다.
대가 — 보낸 것을 답이 올 때까지 손에 들고 있어야 해서 보내는 쪽 메모리가 그만큼 듭니다. 상한을 잘못 잡으면 회선이 남는데도 놀거나, 받는 쪽이 밀려 데이터가 버려집니다.
상세
이 절은 번호를 매긴 데이터가 한 줄로 늘어서 있다고 봅니다. 그 줄 위에서 창이 무엇을 가르고 언제 앞으로 밀리는지를 따라갑니다. 데이터를 순서대로, 잃지 않고 나르는 프로토콜은 대개 이 방식을 씁니다. TCP(Transmission Control Protocol, 전송 제어 프로토콜)가 그 대표입니다.
번호가 위에서 아래로 이어지는 긴 두루마리에 창틀 하나를 얹었다고 생각해 보세요. 창틀 안에 든 번호만 지금 내보낼 수 있습니다. 앞쪽 번호가 잘 닿았다는 답이 오면 창틀이 그만큼 아래로 밀려갑니다. 아래쪽이 번호가 커지는 쪽이고, 이 편에서 「앞으로」는 그 방향을 가리킵니다.
이 창을 윈도라고도 부릅니다. 표제어에 붙은 「윈도」가 바로 이것입니다. 아래에서는 창으로 씁니다. 창틀의 폭이 상대 사정에 따라 넓어지고 좁아진다는 것은 두루마리 비유가 담지 못하는 대목입니다.
창이 가르는 네 구간
데이터에는 번호가 붙습니다. 받는 쪽이 순서를 맞추고 무엇이 빠졌는지 알려면 번호가 있어야 합니다. 이 번호가 순서 번호입니다.
번호가 매겨진 그 줄을 창이 네 구간으로 가릅니다.
flowchart TD
A["1~4번 · 답까지 받았다"]
subgraph 창
B["5~7번 · 보냈고 답을 기다린다"]
C["8~10번 · 아직 안 보냈지만 보내도 된다"]
end
D["11번부터 · 창 밖이라 아직 못 보낸다"]
A --- B
B --- C
C --- D
위에서 아래로 번호가 커지는 순서로 놓았습니다. 가운데 둘이 창 안입니다. 위아래 둘은 창 밖입니다.
보내는 쪽에 남은 몫은 창 안의 아래쪽입니다. 보내도 되지만 아직 안 보낸 만큼입니다. 이 남은 몫이 0이 되면 답이 올 때까지 더 내보낼 수 없습니다.
창이 앞으로 밀리는 때
받는 쪽은 데이터를 받으면 여기까지 받았다고 짧은 답장을 보냅니다. 이 답장이 확인 응답입니다.
확인 응답이 오면 그 번호까지는 다시 보낼 일이 없어집니다. 그래서 창의 위쪽 끝이 그만큼 아래로 옮겨 갑니다. 폭이 그대로라면 아래쪽 끝도 같이 밀려 새 번호가 창 안으로 들어옵니다.
앞 그림을 그대로 출발 상태로 놓고 따라가 보겠습니다. 창은 5번부터 10번까지 여섯 칸이고, 아직 안 보낸 8·9·10 이 남은 몫입니다.
flowchart TD
subgraph S1["① 남은 몫 3 — 8·9·10 을 보낼 수 있다"]
A0["1~4번 · 답까지 받았다"]
A1["5~7번 · 보냈고 답을 기다린다"]
A2["8~10번 · 보내도 된다"]
A3["11번부터 · 창 밖"]
A0 --- A1
A1 --- A2
A2 --- A3
end
subgraph S2["② 8·9·10 을 보냈다 — 남은 몫 0, 멈춘다"]
B0["1~4번 · 답까지 받았다"]
B1["5~10번 · 보냈고 답을 기다린다"]
B3["11번부터 · 창 밖"]
B0 --- B1
B1 --- B3
end
subgraph S3["③ 5번의 답이 왔다 — 창이 한 칸 아래로 밀린다"]
C0["1~5번 · 답까지 받았다"]
C1["6~10번 · 보냈고 답을 기다린다"]
C2["11번 · 보내도 된다"]
C3["12번부터 · 창 밖"]
C0 --- C1
C1 --- C2
C2 --- C3
end
S1 --> S2
S2 --> S3
세 장에서 번호는 같은 순서로 놓여 있고 창만 한 칸 내려갔습니다. 밀리는 것은 창이지 데이터가 아닙니다. 데이터는 처음 매긴 번호를 그대로 답니다. 창이 계속 밀리는 한 보내는 쪽은 멈추지 않고 내보낼 수 있습니다.
창 폭을 정하는 두 상한
창 폭을 정하는 상한은 둘입니다. 하나는 받는 쪽이 알려 주는 여유입니다. 다른 하나는 보내는 쪽이 망 사정을 보고 스스로 잡는 값입니다.
받는 쪽이 알려 주는 이 여유가 수신 윈도입니다. 받아 놓았지만 프로그램이 아직 읽어 가지 않은 데이터가 쌓이는 버퍼의 남은 공간입니다. 이것은 앞에서 말한 보내는 쪽의 남은 몫과 다른 값입니다.
받는 쪽 여유를 넘지 않게 맞추는 일이 흐름 제어입니다. 상대가 읽어 가는 속도보다 빠르게 보내면 받는 쪽 버퍼가 넘칩니다. 넘친 데이터는 그대로 버려집니다.
보내는 쪽이 스스로 잡는 값은 혼잡 윈도입니다. 중간 장비가 밀려 데이터가 버려지고 있는지를 답이 오는 모양으로 짐작해서 정합니다.
답이 늦거나 아예 안 오면 중간이 밀린 것으로 봅니다. 그때는 값을 내립니다. 잘 오는 동안은 조금씩 올립니다. 이렇게 망 사정에 맞춰 보내는 양을 조절하는 일이 혼잡 제어입니다.
보내는 쪽은 두 값 가운데 작은 쪽을 창 폭으로 씁니다. 상대가 더 받을 수 있어도 망이 못 견디면 소용이 없습니다. 망이 한가해도 상대가 못 받으면 마찬가지입니다.
창이 멈추는 때
답이 오지 않으면 창이 안 밀립니다. 창이 안 밀린 채로 남은 몫까지 0이 되면 보내는 쪽은 아무것도 못 내보냅니다. 거기서 멈춥니다.
한동안 답이 안 오면 보내는 쪽은 그 데이터가 없어졌다고 판단합니다. 그래서 같은 것을 다시 내보냅니다. 이 동작이 재전송입니다. 창은 재전송한 것의 답이 와야 비로소 밀립니다.
받는 쪽 여유가 0으로 내려가 창 폭 자체가 0이 되는 때도 있습니다. 이것을 널 윈도라고 부릅니다. 이때는 여유가 생겼다는 새 알림이 올 때까지 보내는 쪽이 기다립니다.
멈추는 까닭이 둘이고 풀리는 길도 둘입니다. 어느 멈춤이 어느 길로 풀리는지 모아 보면 이렇습니다.
stateDiagram-v2
state "창이 밀리는 중" as 밀림
state "멈춤 · 남은 몫 0" as 멈춤
state "재전송" as 재전송
state "널 윈도 · 창 폭 0" as 널윈도
밀림 --> 멈춤 : 남은 몫이 0이 됨
멈춤 --> 밀림 : 확인 응답 도착
멈춤 --> 재전송 : 한동안 답 없음
재전송 --> 밀림 : 재전송한 것의 답 도착
밀림 --> 널윈도 : 받는 쪽 여유 0 알림
널윈도 --> 밀림 : 여유가 생겼다는 새 알림
어느 길로 풀리든 창이 다시 밀리는 상태로 돌아옵니다. 그때까지 보내는 쪽은 새 데이터를 못 내보냅니다.
창 폭을 얼마로 잡나
창이 좁으면 답을 기다리느라 회선이 놉니다. 답 하나가 오가는 데 걸리는 시간을 왕복 시간이라고 합니다. 그 시간 동안 내보낼 수 있는 양보다 창이 좁으면 남는 만큼 회선이 빕니다.
왕복 시간 동안 내보낼 수 있는 이 양을 대역폭 지연 곱이라고 부릅니다. 회선이 넓을수록, 오가는 데 오래 걸릴수록 이 값이 커집니다.
창이 넓으면 반대편 대가가 생깁니다. 보낸 것을 답이 올 때까지 들고 있을 메모리가 늡니다. 한꺼번에 밀려 버려지는 양도 커집니다.
그래서 기준은 대역폭 지연 곱만큼입니다. 거기서 쓸 수 있는 메모리와 손실 위험을 따져 깎습니다.
한 덩이씩 주고받는 방식과 견줄 때
하나 보내고 답을 기다리기를 되풀이하는 방식이 정지 대기입니다. 만들기가 훨씬 간단합니다. 보낸 것도 하나만 들고 있으면 됩니다.
창을 쓰는 값어치는 왕복 시간이 길수록, 회선이 넓을수록 커집니다. 반대로 한 번에 한 덩이만 오가면 되는 짧은 요청과 응답에서는 창을 넓혀도 채울 데이터가 없습니다. 이럴 때는 창을 관리하는 품만 남습니다.
같은 이름을 쓰는 다른 분야
구간이 앞으로 미끄러진다는 그림이 워낙 쓸모가 있어서 다른 데서도 같은 이름을 씁니다.
속도 제한에서는 지금부터 거슬러 일정 시간 동안 들어온 요청을 세는 방식을 이렇게 부릅니다. 시간을 1분 칸으로 끊어 세면 칸이 바뀌는 순간에 두 칸치 요청이 한꺼번에 몰려도 못 잡습니다. 지금부터 거슬러 1분을 세면 그 틈이 없습니다.
배열이나 문자열을 훑는 기법에서도 그렇습니다. 구간의 양 끝을 한 방향으로만 밀어 답을 갱신하면 한 번 훑기로 끝납니다. 이 방법을 투 포인터라고도 부릅니다.
셋 다 「정해진 폭의 구간이 한 방향으로만 움직인다」는 점은 같습니다. 다만 데이터를 나르는 쪽에서는 창이 답을 받아야 밀립니다. 나머지 둘에서는 시간이나 훑는 지점이 밀립니다.
관련 항목
이 방식이 안에서 도는 프로토콜
창 폭을 정하는 상한
수신 윈도 · 혼잡 윈도 · 윈도 크기 · 윈도 스케일링 · 대역폭 지연 곱 · 전송 중 데이터량
창을 앞으로 미는 신호
확인 응답 · 순서 번호 · 누적 확인 응답 · 선택적 확인 응답 · 중복 확인 응답
창이 멈췄을 때 도는 복구 동작
재전송 · 재전송 타임아웃 · 널 윈도 · 윈도 탐색 · fast retransmit
이 방식으로 이루는 전송 제어
흐름 제어 · 혼잡 제어 · 순서 보장 · 신뢰성 · 바이트 스트림
창을 다루는 방식의 갈래
정지 대기 · Go-Back-N · 선택적 반복 · 파이프라이닝
같은 이름을 쓰는 다른 기법
속도 제한 · 고정 윈도우 · 슬라이딩 윈도우 로그 · 투 포인터 · 윈도 집계
창 폭이 모자랄 때 겉으로 나타나는 증상
왕복 시간 · 처리량 · 백프레셔 · 헤드 오브 라인 블로킹 · 지연 시간
다른 이름: 슬라이딩 윈도우 · sliding window