사전 혼잡 제어
개념

혼잡 제어

gabury1고친 사람 github-actions[bot]

혼잡 제어는 보내는 쪽이 망 사정을 살펴 보내는 속도를 스스로 줄이는 일입니다. 망이 감당할 만큼만 내보내서 데이터가 버려지는 것을 막습니다. 같은 망을 쓰는 모두가 함께 줄이기 때문에 남는 길을 나눠 쓰게 됩니다.

쉽고 빠른 이해

혼잡 제어는 망이 막혔다 싶으면 보내는 쪽이 알아서 속도를 낮추는 장치입니다. 파일을 내려받는 도중에 데이터가 사라지기 시작하면, 받는 쪽이 부탁하지 않아도 보내는 쪽이 전송량을 줄입니다.

이게 없으면 망이 막힐수록 상황이 더 나빠집니다. 보낸 것이 버려지고, 버려진 것을 다시 보내고, 그 재전송이 망을 더 막습니다. 결국 선로는 꽉 찼는데 목적지에 닿는 데이터는 거의 없는 상태가 됩니다.

어떻게 도나:

  1. 보내는 쪽이 「한 번에 이만큼까지」라는 상한을 들고 시작합니다
  2. 보낸 것이 잘 도착하면 상한을 조금 올립니다
  3. 사라진 것이 보이면 상한을 크게 내립니다

대가는 속도를 못 채우는 구간이 생긴다는 것입니다. 망이 넉넉해도 상한을 조금씩만 올리므로 한동안은 쓸 수 있는 길보다 적게 씁니다. 잠깐 끊긴 것을 혼잡으로 잘못 읽고 속도를 내리기도 합니다.

상세

점심때 붐비는 식당에서는 손님이 직원을 불러도 그 부름이 소음에 묻혀 사라집니다. 대답을 못 들은 손님들이 한 번 더 부를수록 직원은 더 많이 놓칩니다. 끝내 홀은 부르는 소리로 가득한 채 음식은 거의 나가지 않습니다.

데이터를 보내는 쪽은 망 안을 볼 수 없습니다. 지금 막혔는지를 짐작해야 합니다.

혼잡 제어는 보내는 쪽이 그 짐작을 근거로 한 번에 내보낼 양을 계속 고쳐 잡는 일입니다. 네트워크가 감당할 만큼만 내보내는 것이 목표입니다. 파일을 내려받는 중에 데이터가 사라지기 시작하면 받는 쪽이 요청하지 않아도 보내는 쪽이 속도를 낮추는 것이 그 동작입니다.

여기서 혼잡은 망으로 들어오는 데이터가 망이 내보낼 수 있는 양보다 많아진 상태를 뜻합니다. 넘친 데이터는 줄을 서는 것이 아니라 버려집니다.

망이 막힌다는 것

데이터는 목적지까지 한 번에 가지 않고 라우터를 여럿 거칩니다. 라우터는 들어온 데이터를 보고 다음 장비로 넘겨주는 장비입니다. 넘기는 속도보다 들어오는 속도가 빠르면 못 넘긴 것이 대기열에 쌓입니다.

대기열은 라우터가 미처 못 넘긴 데이터를 잠시 쌓아 두는 공간입니다. 이 공간에는 끝이 있습니다. 꽉 찬 뒤에 도착한 데이터는 들어갈 곳이 없어 버려집니다.

그래서 망이 막히면 두 가지가 같이 나빠집니다. 대기열에서 차례를 기다리는 시간만큼 지연이 늘고, 대기열이 넘치는 순간부터 패킷 손실이 납니다. 보내는 쪽이 보는 것은 이 둘뿐입니다.

혼잡 붕괴

여기서 아무도 속도를 안 줄이면 망은 저절로 낫지 않습니다. 오히려 스스로 더 나빠지는 쪽으로 돕니다.

사라진 데이터는 재전송으로 다시 나갑니다. 재전송도 같은 망을 지나므로 망에 들어오는 양이 또 늘어납니다. 늘어난 만큼 대기열이 더 빨리 넘치고, 넘친 만큼 재전송이 또 늘어납니다.

flowchart TD
    A["보내는 쪽이 속도를 안 줄인다"] --> B["라우터 대기열이 넘친다"]
    B --> C["데이터가 버려진다"]
    C --> D["버려진 것을 다시 보낸다"]
    D --> A

이 고리가 굳어져서 선로는 꽉 찼는데 목적지에 닿는 데이터는 거의 없는 상태를 혼잡 붕괴라고 부릅니다. 혼잡 제어가 존재하는 까닭이 이것입니다. 개별 연결이 조금 느려지는 것을 받아들여 망 전체가 무너지는 것을 막습니다.

흐름 제어와 가르는 선

혼잡 제어와 헷갈리기 쉬운 이웃이 흐름 제어입니다. 둘 다 보내는 쪽의 속도를 늦추는 장치라서 이름만 보면 구분이 안 갑니다.

가르는 것은 누구를 배려하느냐입니다. 흐름 제어는 받는 쪽이 감당 못 할까 봐 늦추고, 혼잡 제어는 중간 망이 감당 못 할까 봐 늦춥니다.

흐름 제어 혼잡 제어
지키려는 대상 받는 쪽의 저장 공간 중간 망의 대기열
얼마나 보낼지 정하는 쪽 받는 쪽이 알려 줍니다 보내는 쪽이 짐작합니다
넘겼을 때 받는 쪽에서 넘칩니다 라우터에서 버려집니다

실제로 보낼 양은 둘 중 작은 쪽을 따릅니다. 받는 쪽이 넉넉해도 망이 막혔으면 못 보내고, 망이 한가해도 받는 쪽이 벅차면 못 보냅니다.

보낼 양을 담는 혼잡 윈도

보내는 쪽은 「한 번에 여기까지는 보내도 된다」는 상한을 하나 들고 있습니다. 이 상한을 혼잡 윈도라고 부릅니다. 혼잡 제어가 하는 일은 사실상 이 값 하나를 올리고 내리는 것입니다.

상한이 붙는 대상은 보낸 뒤 아직 확인 응답을 못 받은 데이터의 양입니다. 확인 응답은 받는 쪽이 「여기까지 받았다」고 알려 주는 짧은 답장입니다. 답장이 안 온 데이터가 상한만큼 쌓이면 보내는 쪽은 더 보내지 않고 기다립니다.

받는 쪽이 알려 주는 상한은 수신 윈도라고 따로 부릅니다. 보내는 쪽은 두 상한 가운데 작은 쪽을 씁니다.

망 사정을 읽는 신호

보내는 쪽은 망 안을 못 보므로 손에 들어오는 것만으로 짐작합니다. 짐작의 바탕이 되는 값이 왕복 시간입니다. 왕복 시간은 데이터를 보내고 그 확인 응답을 받기까지 걸리는 시간입니다.

이 값을 놓고 읽을 수 있는 신호는 크게 셋입니다.

신호 어떻게 읽나
답장이 안 옴 대기열이 넘쳐 버려졌다고 봅니다. 가장 널리 쓰는 신호입니다
왕복 시간이 길어짐 대기열에 줄이 생겼다고 봅니다. 버려지기 전에 알아챕니다
라우터가 붙인 표시 막히기 시작했다고 라우터가 직접 알려 준 것입니다

첫째 신호는 기다림으로 읽습니다. 왕복 시간을 넘겨 한참 기다려도 답장이 없으면 보내는 쪽은 그 데이터가 사라졌다고 판단합니다.

셋째는 라우터가 버리는 대신 데이터에 표를 하나 찍어 보내는 방식입니다. 이 표를 명시적 혼잡 알림이라고 부릅니다. 버리지 않고 알리므로 재전송 없이 속도만 낮출 수 있습니다.

조금씩 늘리고 크게 줄이기

신호를 읽은 뒤 상한을 어떻게 움직이느냐가 남았습니다. 널리 쓰는 방식은 올릴 때와 내릴 때의 폭을 다르게 잡습니다. 올릴 때는 일정한 값을 더하고, 내릴 때는 일정한 비율로 나눕니다.

이 방식을 AIMD(Additive Increase Multiplicative Decrease, 더하기로 늘리고 곱하기로 줄이기)라고 부릅니다. 아래는 상한이 움직이는 모양을 의사 코드로 적은 것입니다. 오른쪽 주석이 그때의 값입니다.

혼잡 윈도 = 10           // 10

// 왕복 한 번이 무사히 끝날 때마다
혼잡 윈도 = 혼잡 윈도 + 1  // 11
혼잡 윈도 = 혼잡 윈도 + 1  // 12

// 사라진 데이터를 보면
혼잡 윈도 = 혼잡 윈도 / 2  // 6

폭을 다르게 잡는 까닭은 두 실수의 값이 다르기 때문입니다. 너무 조심해서 생기는 손해는 선로를 덜 쓰는 것뿐이지만, 너무 욕심내서 생기는 손해는 망 전체의 붕괴입니다. 그래서 위험한 쪽으로는 천천히 가고 안전한 쪽으로는 단숨에 물러섭니다.

이 방식은 같은 망을 쓰는 연결들이 비슷한 몫으로 수렴한다는 성질도 함께 가집니다. 많이 보내던 연결일수록 반으로 나눌 때 더 많이 잃기 때문입니다.

세 단계

상한을 처음부터 AIMD 로만 올리면 제 속도에 닿기까지 너무 오래 걸립니다. 그래서 대개 연결을 시작할 때는 다른 규칙을 씁니다.

시작 구간에서는 확인 응답이 올 때마다 상한을 곱으로 키웁니다. 이 구간을 느린 시작이라고 부릅니다. 영어로는 slow start 라고 합니다. 시작하는 값이 작다는 뜻이지 올라가는 속도가 느리다는 뜻이 아닙니다.

어느 문턱을 넘거나 손실을 보면 혼잡 회피 구간으로 넘어갑니다. 이 구간이 앞에서 본 AIMD 입니다. 상한을 한 번에 키우지 않고 왕복마다 조금씩 더합니다.

손실에도 두 모습이 있습니다. 중간 하나만 빠지면 받는 쪽은 그 뒤 데이터를 계속 받으면서 같은 곳을 가리키는 답장을 되풀이해 보냅니다. 이 되풀이되는 답장을 중복 확인 응답이라고 부릅니다.

중복 확인 응답이 온다는 것은 길이 아직 살아 있다는 뜻입니다. 이때는 빠른 회복 구간으로 가서 빠진 것만 채우고, 상한을 바닥까지 떨어뜨리지 않은 채 혼잡 회피로 돌아옵니다.

답장이 아예 끊기면 다릅니다. 기다리는 시간이 다 지나도록 아무것도 안 오면 길이 막혔다고 보고 느린 시작으로 되돌아갑니다.

stateDiagram-v2
    state "느린 시작" as SS
    state "혼잡 회피" as CA
    state "빠른 회복" as FR
    [*] --> SS
    SS --> CA: 문턱을 넘었다
    CA --> FR: 중복 확인 응답을 보았다
    FR --> CA: 빠진 조각이 채워졌다
    CA --> SS: 기다려도 답장이 안 온다

그림은 연결 하나가 도는 동안 세 구간을 오가는 모양입니다. 출발은 언제나 느린 시작이고, 답장이 끊길 때마다 거기로 되돌아옵니다.

모두가 같이 지켜야 하는 규칙

혼잡 제어는 망 장비가 강제하는 것이 아니라 양 끝의 프로그램이 지키는 약속입니다. 라우터는 넘치면 버릴 뿐 누구에게도 속도를 낮추라고 명령하지 않습니다.

그래서 한쪽만 안 지키면 그쪽이 더 많이 가져갑니다. 다들 반으로 줄일 때 혼자 안 줄이면 남이 비운 공간을 차지하기 때문입니다.

새 혼잡 제어 방식을 만들 때 기존 방식과 나란히 놓고 몫이 한쪽으로 쏠리지 않는지를 보는 까닭이 이것입니다. 이 성질을 공정성이라고 부릅니다.

혼잡 제어를 거는 통신과 안 거는 통신

한 바이트도 빠지면 안 되고 오래 이어지는 전송에는 혼잡 제어를 겁니다. TCP(Transmission Control Protocol, 전송 제어 프로토콜)가 대표입니다. 파일 전송이나 웹 페이지 내려받기처럼 처리량이 중요한 일이 여기 해당합니다.

짧게 한 번 묻고 한 번 답하는 통신에는 걸 것이 거의 없습니다. 상한을 올릴 틈도 없이 교환이 끝나기 때문입니다. UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜)는 혼잡 제어 장치를 자체에 두지 않습니다.

다만 UDP 위에서 데이터를 오래 밀어 넣는 프로그램은 혼잡 제어를 직접 만들어 넣어야 합니다. 안 넣으면 그 프로그램이 망을 막는 쪽이 되고, 옆에서 규칙을 지키는 연결들만 밀려납니다.

실시간 음성이나 영상처럼 늦게 오느니 빠지는 편이 나은 통신은 중간에 섭니다. 속도를 아예 안 줄이면 망을 해치고, 손실이 보일 때마다 반으로 줄이면 소리가 끊깁니다. 그래서 화질이나 음질을 낮추는 쪽으로 보낼 양을 줄이는 방식을 따로 씁니다.

관련 항목

혼잡 제어를 품고 도는 프로토콜

TCP · QUIC · UDP · SCTP · DCCP · 전송 계층

혼잡 제어가 쓰는 이름 붙은 알고리즘

느린 시작 · 혼잡 회피 · 빠른 회복 · fast retransmit · AIMD · TCP Reno · TCP Tahoe · CUBIC · BBR · TCP Vegas

혼잡 제어가 올리고 내리는 값

혼잡 윈도 · 수신 윈도 · 느린 시작 문턱 · 전송 중 데이터량 · 왕복 시간 · 재전송 타임아웃 · 대역폭 지연 곱

혼잡 제어가 망 사정을 읽는 신호

패킷 손실 · 중복 확인 응답 · 확인 응답 · ECN · 지연 · 지터

혼잡 제어가 없을 때 망에서 나는 고장

혼잡 · 혼잡 붕괴 · 망 혼잡 · 대기열 · 꼬리 버림 · 버퍼블로트

혼잡 제어와 나란히 도는 다른 제어

흐름 제어 · 재전송 · 슬라이딩 윈도 · 순서 번호 · 오류 검출 · 신뢰성

혼잡 제어를 재고 견주는 지표

처리량 · 대역폭 · 공정성 · TCP 친화성 · 머리줄 막힘

혼잡 제어가 기대는 망 장비와 구조

라우터 · 능동 대기열 관리 · 병목 링크 · 패킷 교환 · 네트워크

다른 이름: congestion control · 혼잡제어