1. Bufferbloat

병목구간(bottleneck)이란, 인터넷을 이용하는 Client와 인터넷 Server 사이에 존재하는 네트워크 구간 중 가장 bandwidth가 작은 구간을 말한다.

인터넷 초창기엔 서버의 media speed, 스위치나 라우터의 interface/home edge단 link가 모두 100Mbps(Fast Ethernet)이었기에 병목구간이 큰 문제로 부각되지 않았다. 하지만 Gigabit ethernet이 나오면서 상황이 달라졌다. 이전에는 64Kbyte의 window size로 충분히 성능을 낼 수 있었지만, 이후 인터넷 속도가 올라감에 따라 window size를 올릴 수 밖에 없었기 때문이다. (RFC 1323)

서버의 media speed나 상위 네트워크가 1G로 바뀜에 따라 WiFi AP/Microwave 장비 등이 병목구간이 되었다. 이에 Speed mismatch에 의한 buffer overflow가 빈번히 발생하면서 Throughput 저하, 잦은 재전송 등 link 효율이 감소하게 되었다. 특히, packet drop의 경우 TCP 통신상의 속도(Throughput)에 치명적일 수 있었다.

이에 제조사들은 메모리 가격 하락 등의 외부 요인을 반영하여 Buffer 메모리를 크게 늘리는 형태로 대응하였지만 이는 또다른 문제를 낳았다. 여러 명이 동시 접속해서 사용하는 WiFi의 경우 buffer는 큰 데 비해 bandwidth가 작아, 한 유저가 file을 다운로드 받는 경우에 WiFi AP의 buffer가 그 유저의 데이터로 가득 차버리는 등의 문제가 발생하였다. 이에 다른 유저가 동일 WiFi를 사용할 경우 인터넷 접속 Ack가 buffer의 맨 뒤에 쌓여, 최대 buffering delay가 수백 ms에서 수초까지 발생하는 등 지연 현상이 발생하였다. 이런 현상을 Bufferbloat이라 한다.

버퍼 크기와 대기
버퍼 크기와 대기작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 2 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 6 손실 0. 작은 큐는 4개를 잃고, 큰 큐는 6번 요청까지 순서대로 전달합니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 2 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 6 손실 0
버퍼 크기와 대기작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 2 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 6 손실 0. 작은 큐는 4개를 잃고, 큰 큐는 6번 요청까지 순서대로 전달합니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 2 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 6 손실 0

작은 큐는 4개를 잃고, 큰 큐는 6번 요청까지 순서대로 전달합니다.

단계별 장면

1. 용량 안의 패킷을 순서대로 받습니다.

버퍼 크기와 대기 · 1작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 출력 · 수신 · 유입 4 대기 2 · 처리 0 손실 2 · × 3, 4 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 3 · 4 · 출력 · 수신 · 유입 4 대기 4 · 처리 0 손실 0. 같은 패킷이 같은 시점에 두 큐로 들어갑니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신12출력수신유입 4 대기 2처리 0 손실 2× 3, 4큰 버퍼 · 6개송신 → FIFO 큐 → 수신1234출력수신유입 4 대기 4처리 0 손실 0
버퍼 크기와 대기 · 1작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 출력 · 수신 · 유입 4 대기 2 · 처리 0 손실 2 · × 3, 4 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 3 · 4 · 출력 · 수신 · 유입 4 대기 4 · 처리 0 손실 0. 같은 패킷이 같은 시점에 두 큐로 들어갑니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신12출력수신유입 4 대기 2처리 0 손실 2× 3, 4큰 버퍼 · 6개송신 → FIFO 큐 → 수신1234출력수신유입 4 대기 4처리 0 손실 0

2. 작은 큐는 초과 패킷을 버립니다. 큰 큐의 6번 요청은 앞선 5개를 기다립니다.

버퍼 크기와 대기 · 2작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 출력 · 수신 · 유입 6 대기 2 · 처리 0 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 3 · 4 · 5 · 6 · 출력 · 수신 · 유입 6 대기 6 · 처리 0 손실 0. 큰 큐의 6번 요청: 앞선 패킷이 나가기를 기다리는 중. 작은 큐에서는 이미 손실됐습니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신12출력수신유입 6 대기 2처리 0 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신123456출력수신유입 6 대기 6처리 0 손실 0
버퍼 크기와 대기 · 2작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 출력 · 수신 · 유입 6 대기 2 · 처리 0 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 1 · 2 · 3 · 4 · 5 · 6 · 출력 · 수신 · 유입 6 대기 6 · 처리 0 손실 0. 큰 큐의 6번 요청: 앞선 패킷이 나가기를 기다리는 중. 작은 큐에서는 이미 손실됐습니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신12출력수신유입 6 대기 2처리 0 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신123456출력수신유입 6 대기 6처리 0 손실 0

3. 작은 큐: 처리 2 · 손실 4. 큰 큐: 처리 6 · 손실 0. 같은 입력에서 손실과 대기를 구분합니다.

버퍼 크기와 대기 · 3작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 2 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 6 손실 0. 작은 큐는 4개를 잃고, 큰 큐는 6번 요청까지 순서대로 전달합니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 2 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 6 손실 0
버퍼 크기와 대기 · 3작은 버퍼 · 2개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 2 손실 4 · × 3, 4, 5, 6 · 큰 버퍼 · 6개 · 송신 → FIFO 큐 → 수신 · 출력 · 수신 · 유입 6 대기 0 · 처리 6 손실 0. 작은 큐는 4개를 잃고, 큰 큐는 6번 요청까지 순서대로 전달합니다.작은 버퍼 · 2개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 2 손실 4× 3, 4, 5, 6큰 버퍼 · 6개송신 → FIFO 큐 → 수신출력수신유입 6 대기 0처리 6 손실 0
같은 6개 패킷 · FIFO 용량 2 / 6개 · 동일 출력 간격. 6번은 짧은 요청입니다. 설명용 사건이며 재전송은 생략합니다.
원본 도해

2. 한번에 얼마나 보낼 수 있을까

  • 처리량 = (한번에 보낼수 있는 양) * (단위시간 / 왕복에 걸리는 시간)

  • Throughput = Window Size / RTT

예를 들어 병목구간이 100Mbps Ethernet이고, Client와 서버의 RTT는 40ms 상황을 가정해보면,

100Mbps(bandwidth, 처리량) * 40ms(delay, RTT) = 10000000 * 0.04 = 4000000 bits = 500Kbytes

즉, 이 경우 100Mbps 속도로 40ms 동안 보낼 수 있는 데이터가 500Kbytes이기 때문에 Window size가 500Kbytes로 끊김없이 서버에서 계속 데이터를 보낼 경우, 병목구간 100Mbps를 하나의 세션이 모두 사용하게 된다. 이와 같이 병목구간의 bandwidth를 최대한 다 사용할 수 있는 window size를 BDP(Bandwidth Delay Product)라 한다.

3. Buffer overflow

  • 처리량 = (한번에 보낼수 있는 양) * (단위시간 / 왕복에 걸리는 시간)

  • Throughput = Window Size / RTT

반면, buffer가 매우 작은 경우, 가령 위의 예에서 병목구간의 buffer가 64KBytes인 경우 buffer overflow가 발생한다.

Throughput = 64KB / 0.04(sec) = 12.8Mbps 이므로, 100Mbps link를 최대한 활용하지 않을 뿐더러 서버의 media bandwidth가 1G 일 경우 speed mismatch에 의한 buffer overflow가 발생한다.  (구글의 BBR은 buffer가 작을 경우를 고려하진 않았다고 보인다.)

앞으로 상이한 네트워크 환경(IoT vs 100G 이상)이 공존하게 될 것을 고려해보면, 해당 이슈들에 대한 논의도 많이 다루게 되지 않을까 싶다.