사전 흐름 제어
개념

흐름 제어

gabury1고친 사람 github-actions[bot]

흐름 제어는 받는 쪽이 감당할 만큼만 보내도록 보내는 쪽의 속도를 맞추는 일입니다. 받는 쪽이 지금 얼마나 더 받을 수 있는지를 알려 주면 보내는 쪽은 그만큼만 내보내고 멈춥니다. 미처 처리하지 못한 데이터가 받는 쪽에서 넘쳐 버려지는 일을 막습니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 보내는 속도를 받는 쪽의 처리 속도에 맞춥니다. 받는 쪽이 「지금 8000바이트 더 받을 수 있다」고 알리면 보내는 쪽은 8000바이트까지만 보냅니다.

왜 이렇게 하나 — 도착한 데이터는 프로그램이 읽어 갈 때까지 받는 쪽 메모리에 쌓입니다. 그 공간이 차면 뒤에 온 데이터는 버려집니다. 버려진 만큼 다시 보내야 하니 망을 두 번 씁니다.

어떻게 도나

  1. 받는 쪽이 남은 공간의 크기를 보내는 쪽에 알립니다
  2. 보내는 쪽은 아직 받았다는 답을 못 들은 양이 그 크기를 넘지 않게 합니다
  3. 받는 쪽이 데이터를 읽어 가 공간이 생기면 새 크기를 다시 알립니다

대가 — 허락된 양을 다 보낸 보내는 쪽은 새 알림이 올 때까지 멈춥니다. 알림이 오가는 데 걸리는 시간이 길면 회선이 비어 있어도 놀게 됩니다.

상세

이 절은 흐름 제어가 무엇과 무엇의 속도를 맞추는 일인지부터 봅니다. 그다음 받는 쪽이 남은 공간을 어떻게 알리고 보내는 쪽이 그 수를 어떻게 쓰는지를 데이터를 주고받는 두 컴퓨터로 따라갑니다.

끝에서는 이름이 닮은 혼잡 제어와 어디서 갈리는지, 그리고 전송 계층 말고 어디에서 같은 일이 벌어지는지를 짚습니다.

주전자로 컵에 물을 따르는 장면을 떠올리면 쉽습니다. 컵을 든 사람이 「아직 반밖에 안 찼다」고 말해 주면 따르는 사람은 그 남은 만큼만 붓습니다. 아무 말도 안 해 주면 따르는 사람은 컵이 넘칠 때까지 계속 붓고, 넘친 물은 바닥으로 갑니다.

받는 쪽에 쌓이는 데이터

데이터가 도착하는 것과 프로그램이 그 데이터를 읽어 가는 것은 따로 놉니다. 도착은 망이 정하는 속도로 일어나고, 읽어 가는 것은 프로그램이 바쁜 정도가 정합니다.

그래서 받는 쪽은 도착한 데이터를 잠시 담아 둘 메모리를 둡니다. 이것이 수신 버퍼입니다. 프로그램이 아직 읽어 가지 않은 데이터가 여기 머물다가, 읽어 가면 그만큼 공간이 비워집니다.

버퍼가 가득 차면 그다음에 도착한 데이터는 담을 곳이 없어 버려집니다. 버려진 데이터는 보내는 쪽이 다시 보내야 하고, 그 재전송은 같은 데이터를 두 번 나르는 일입니다.

flowchart TD
    A["도착한 데이터"] --> B["수신 버퍼에 쌓인다"]
    B --> C["프로그램이 읽어 간다"]
    C -->|공간이 비워진다| B
    B -->|가득 찼다| D["뒤에 온 데이터는 버려진다"]

그림에서 오른쪽 아래로 빠지는 길이 흐름 제어가 막으려는 길입니다. 보내는 쪽의 속도가 「프로그램이 읽어 가는 속도」를 넘어서면 그 길로 데이터가 샙니다.

남은 공간을 숫자로 알린다

받는 쪽은 자기 버퍼에 남은 공간의 크기를 보내는 쪽에 알립니다. 이 수를 윈도라고 부릅니다. 데이터를 받았다는 답장에 이 수를 같이 실어 보내는 것이 흔한 방식입니다.

보내는 쪽은 이 수를 상한으로 씁니다. 보냈지만 아직 받았다는 답을 못 들은 데이터의 양이 그 수를 넘지 않게 합니다. 답을 들은 만큼 그 양이 줄고, 줄어든 만큼 새로 보낼 수 있습니다.

sequenceDiagram
    participant 보내는쪽
    participant 받는쪽
    받는쪽->>보내는쪽: 8000바이트 더 받을 수 있다
    보내는쪽->>받는쪽: 8000바이트를 보낸다
    Note over 보내는쪽,받는쪽: 허락된 만큼 다 보냈으니 보내는 쪽은 여기서 멈춘다
    받는쪽->>보내는쪽: 4000바이트를 읽어 갔다. 4000바이트 더 받을 수 있다
    보내는쪽->>받는쪽: 4000바이트를 보낸다

허락된 양이 답장과 함께 앞으로 밀려 가는 이 모양을 슬라이딩 윈도라고 부릅니다. 보내도 되는 구간이 창문처럼 데이터 위를 미끄러진다는 뜻입니다.

이 방식은 한 덩이씩 주고받는 것보다 회선을 잘 씁니다. 답장을 기다리는 동안에도 허락된 양이 남아 있으면 계속 내보낼 수 있기 때문입니다.

멈췄다가 다시 도는 때

받는 쪽 프로그램이 데이터를 한동안 안 읽어 가면 버퍼가 차고 남은 공간은 0이 됩니다. 이때 받는 쪽은 0을 알리고, 보내는 쪽은 새 알림이 올 때까지 데이터를 내보내지 않습니다.

문제는 그 새 알림도 망을 지나오다 사라질 수 있다는 것입니다. 받는 쪽은 알렸다고 여기고 보내는 쪽은 못 들어 기다립니다. 둘이 서로를 기다리며 굳는 데드락이 됩니다.

그래서 보내는 쪽은 멈춰 있는 동안에도 이따금 아주 작은 데이터를 보내 「지금은 얼마나 받을 수 있나」를 물어봅니다. 답에 새 크기가 실려 오면 다시 돌기 시작합니다.

stateDiagram-v2
    [*] --> 보냄
    보냄 --> 멈춤: 허락된 크기를 다 썼다
    멈춤 --> 보냄: 새 크기가 실린 답이 왔다
    멈춤 --> 물어봄: 알림이 오지 않는다
    물어봄 --> 멈춤: 아직 0이다
    물어봄 --> 보냄: 새 크기가 실린 답이 왔다

혼잡 제어와 갈리는 지점

이름이 닮은 혼잡 제어도 보내는 속도를 줄이는 일입니다. 둘을 가르는 것은 누구의 한계를 보느냐입니다. 흐름 제어는 받는 쪽 한 대를 보고, 혼잡 제어는 두 컴퓨터 사이에 놓인 망을 봅니다.

흐름 제어 혼잡 제어
누구의 한계인가 받는 쪽 한 대의 처리 속도 중간에 놓인 망의 처리 속도
누가 알려 주나 받는 쪽이 숫자로 알려 준다 알려 주는 쪽이 없다. 보내는 쪽이 손실과 지연으로 짐작한다
못 지키면 받는 쪽 버퍼가 넘쳐 데이터가 버려진다 중간 장비의 큐가 넘쳐 데이터가 버려진다

보내는 쪽은 두 수를 모두 들고 있다가 작은 쪽만큼만 내보냅니다. 받는 쪽이 넉넉히 받을 수 있어도 망이 막혀 있으면 망에 맞추고, 망이 한가해도 받는 쪽이 못 따라가면 받는 쪽에 맞춥니다.

회선이 노는 대가

허락된 크기를 다 쓴 보내는 쪽은 새 알림이 올 때까지 멈춥니다. 알림이 돌아오는 데 걸리는 시간을 왕복 시간이라고 하는데, 이 시간이 길수록 멈춰 있는 동안이 길어집니다.

그래서 허락된 크기가 작고 왕복 시간이 긴 연결은 회선이 비어 있는데도 데이터가 안 나갑니다. 한 왕복마다 정해진 양밖에 못 보내니 처리량에 상한이 생깁니다.

이 상한을 넓히려면 한 번에 알릴 수 있는 크기를 키워야 합니다. 알림에 쓰는 필드의 폭이 정해져 있는 프로토콜에서는 그 폭을 넓히는 확장을 따로 두기도 합니다. 윈도 스케일링이 그런 확장입니다.

반대쪽 대가도 있습니다. 버퍼를 크게 잡으면 받는 쪽이 멈추는 일은 줄지만, 데이터가 버퍼에서 읽히기를 기다리는 시간이 늘어 지연이 커집니다.

전송 계층 말고 어디에 있나

같은 생각은 여러 곳에서 되풀이됩니다. 공통점은 하나입니다 — 받는 쪽이 「그만」이라고 말할 수 있는 길을 만들어 두는 것입니다.

케이블로 글자를 주고받는 직렬 통신은 두 방식을 씁니다. 하나는 따로 난 선에 신호를 실어 멈추라고 알리는 것이고, 다른 하나는 「멈춰」와 「다시」를 뜻하는 약속된 글자를 데이터에 섞어 보내는 것입니다.

한 연결 위에 여러 스트림을 태우는 프로토콜은 스트림마다 따로 허락된 크기를 둡니다. 한 스트림의 받는 쪽이 느려도 나머지 스트림은 계속 돌게 하려는 것입니다.

프로그램끼리도 같은 일을 합니다. 받는 쪽이 감당 못 할 때 만드는 쪽을 늦추라고 되미는 신호를 백프레셔라고 부릅니다. 웹 서버가 들어오는 요청을 초당 몇 건까지만 받겠다고 정하는 속도 제한도 같은 뿌리입니다.

흐름 제어를 아예 안 두는 프로토콜도 있습니다. UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)는 받는 쪽이 못 따라가도 보내는 속도가 줄지 않습니다. 조절이 필요하면 그 위에 얹힌 프로그램이 직접 해야 합니다.

관련 항목

흐름 제어를 넣거나 뺀 전송 프로토콜

TCP · UDP · QUIC · HTTP-2 · SCTP · 전송 계층

흐름 제어가 쓰는 장치

슬라이딩 윈도 · 윈도 · 윈도 크기 · 수신 버퍼 · 윈도 스케일링 · WINDOW_UPDATE · 널 윈도 · 윈도 탐색

흐름 제어와 함께 도는 전송 기능

확인 응답 · 순서 번호 · 재전송 · 타임아웃 · 혼잡 제어 · 신뢰성 · 세그먼트

흐름 제어가 지키거나 깎는 성능 지표

처리량 · 지연 · 왕복 시간 · 대역폭 · 대역폭 지연 곱

응용 수준에서 같은 일을 하는 수단

백프레셔 · 속도 제한 · 큐 · 버퍼 · 배치 처리

흐름 제어가 어긋날 때 터지는 장애

데드락 · 패킷 손실 · 혼잡 붕괴 · 버퍼 블로트 · 헤드 오브 라인 블로킹

흐름 제어가 나타나는 다른 통신 방식

직렬 통신 · 스트림 · 소켓 · 파이프

다른 이름: flow control · 플로 컨트롤