핵심 인사이트 (3줄 요약)
- 본질: QUIC이 TCP의 치명적인 "재전송 딜레마(칸 알고리즘의 원인)"를 비웃으며 완벽하게 박살 낸 비결은, 재전송할 때 바보같이 옛날 패킷 번호(Seq)를 그대로 재탕하지 않고 **"재전송하는 패킷도 무조건 완전히 새로운 '새 번호표(고유 패킷 번호, Packet Number)'를 부여받아 발사되는 구조"**로 갈아엎은 데 있다.
- 모호성 타파 (Ambiguity Resolution): TCP는 100번을 잃어버려서 재전송할 때 또 똑같이 '100번'이라고 적어 보내서, 나중에 영수증이 오면 "이게 첫 번째 100번의 대답인지, 두 번째 100번의 대답인지" 헷갈려(RTT 오염) 미쳐버렸다. QUIC은 재전송할 때 **"새 번호 105번 (근데 알맹이는 옛날 100번 내용)"**으로 포장해서 쏘므로 절대로 헷갈릴 일이 1도 없다.
- 더 정교한 SACK과 NACK: "어떤 놈이 유실됐고 어떤 놈이 도착했는지"를 수신자가 알려줄 때, TCP는 SACK 블록이 3개밖에 없어서 디테일하게 말 못 했지만, QUIC은 무려 256개의 잃어버린 빈칸 목록을 한 방의 영수증(ACK Frame)에 좍 적어서 송신자에게 완벽한 정답지를 바칠 수 있는 넉넉한 공간을 가졌다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
-
개념: QUIC 프로토콜에서 TCP의 시퀀스 넘버 체계가 가진 재전송 모호성(Retransmission Ambiguity)을 해결하기 위해, 데이터의 오프셋 번호(Stream Offset)와 전송되는 껍데기 번호(Packet Number)를 완전히 분리하여 단조 증가(Monotonically Increasing)하도록 재설계한 패킷 손실 복구 아키텍처.
-
필요성: TCP를 만든 옛날 사람들은 "택배 1번이 사라지면, 다시 1번이라고 써서 보내면 되지"라고 생각했다. 이게 칸(Karn) 알고리즘의 비극을 낳았다. 재전송 영수증인지 늦은 영수증인지 헷갈려서 핑 타임 계산(RTT)이 오염되었다. 구글 천재들은 분노했다. "야! 박스 겉면의 배송 번호표랑, 박스 안에 든 편지지의 내용물 번호표를 완전히 분리해!! 배송 번호표는 한 번 썼으면 영원히 버리고 무조건 새 번호표 뽑아서 딱지 붙여!!" 이 철학의 분리가 혼잡 제어의 정밀도를 100배 끌어올렸다.
-
💡 비유: 고유 패킷 번호(Packet Number) 제도는 식당의 **"재주문 진동벨 시스템"**과 같습니다.
- TCP (구형): 손님이 '15번 진동벨'을 받고 기다리다 제육볶음이 안 나와서 항의했습니다. 주방은 제육볶음을 다시 만들면서 또 '15번 진동벨'을 울립니다. 15번이 울렸을 때, 손님은 이게 첫 번째 시킨 게 나온 건지, 두 번째 시킨 게 나온 건지 헷갈립니다.
- QUIC (신형): 손님이 제육볶음이 안 나와서 항의했습니다. 직원은 기존 15번 진동벨을 폐기하고, 아예 완전히 새로운 **'88번 진동벨(새 Packet Number)'**을 줍니다. "고객님, 88번 울리면 받으러 오세요. (안의 내용물은 똑같은 제육볶음입니다)." 88번이 울리면 헷갈릴 일이 절대 없습니다!
📢 섹션 요약 비유: 패킷 번호와 데이터 번호의 분리는 우편의 "운송장 번호"와 "편지 페이지 번호"의 분리입니다. 편지 제1장(Stream Offset)이 유실되어 다시 보낼 때, 굳이 옛날 운송장 번호를 고집할 필요 없이 무조건 새로운 오늘 자 우체국 운송장 번호(Packet Number)를 발급받아 겉에 붙여 보내면 꼬일 일이 0%입니다.
Ⅱ. QUIC의 완벽한 이중 식별자 시스템 (Deep Dive)
QUIC 패킷을 돋보기로 까보면, TCP가 하나로 퉁치던 번호표가 두 개로 기가 막히게 분리되어 있다.
1. 껍데기의 번호: Packet Number (단조 증가)
패킷 겉면에 찍히는 번호다.
- 규칙은 단 하나: "무조건 1씩 증가한다. 절대 줄어들거나 같은 번호를 두 번 쓰지 않는다 (Strictly Monotonically Increasing)."
- 10번 패킷을 보냈는데 타임아웃이 나서 재전송을 해야 한다?
- 옛날 TCP는 또 10번이라고 써서 보냈다.
- QUIC은? "지금 내가 보낼 차례가 11번이네? 그럼 11번 껍데기에 싸서 보내!"
- 이로 인해 수신자가
ACK 11을 주면, "오, 방금 재전송한 게 0.1초 만에 도착했구나!" 하고 RTT(핑)를 한 치의 오차 없이 완벽하게 소수점 4자리까지 정밀하게 계산해 낼 수 있다. (Karn 알고리즘 따위는 휴지통에 버렸다).
2. 알맹이의 번호: Stream Offset (데이터 조립용)
겉면 껍데기가 11번으로 바뀌어 도착하면 수신자 앱은 조립을 어떻게 할까? 걱정할 필요 없다.
- 11번 껍데기 박스를 까보면, 그 안에
Stream Offset = 500이라고 알맹이의 원래 고유 위치(TCP의 시퀀스 넘버 역할)가 얌전하게 적혀 있다. - 브라우저의 뇌구조: "아~ 박스는 11번으로 왔는데, 뜯어보니 아까 못 받았던 500번째 위치에 들어갈 사진 조각이구나! 쏙 끼워 넣자!"
- 즉, 배송 시스템(Packet Number)과 조립 시스템(Stream Offset)의 역할을 100% 디커플링(분리) 시킨 위대한 설계다.
┌─────────────────────────────────────────────────────────────┐
│ TCP 재전송과 QUIC 재전송의 멘붕 차이 시각화 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [ 구형 TCP의 눈물겨운 재전송 (모호성 폭발) ] │
│ 보냄: (Seq=10) ───(지연)──────────────────────▶ 늦게 도착 │
│ 보냄: (Seq=10) ───(재전송함!)────────▶ 일찍 도착 │
│ │
│ 수신자: "10번 잘 받았어! (ACK 10)" ──▶ 송신자: "? 둘 중 누구 영수증임?"│
│ │
│ [ 최첨단 QUIC의 우아한 재전송 (완벽 해소) ] │
│ 보냄: (PN=10, 알맹이=10) ───(지연)────────────▶ 늦게 도착 │
│ 보냄: (PN=11, 알맹이=10) ───(재전송함!)──▶ 일찍 도착 │
│ │
│ 수신자: "11번 박스 잘 받았어! (ACK 11)" ──▶ 송신자: "오! 11번 영수증이네!│
│ 아까 지연된 건 아직 안 왔고, 방금 재전송한 게 먼저 꽂혔구나!!" │
└─────────────────────────────────────────────────────────────┘
3. 미친 용량의 넉넉한 ACK 블록 (ACK Frame)
TCP의 옵션 칸은 고작 40바이트 제한이라, 이빨 빠진 패킷을 알려주는 SACK 블록을 최대 3개(3 덩어리)밖에 못 적어 보냈다. 10개가 듬성듬성 빠지면 다 말해주지도 못했다.
- QUIC은 헤더 크기 제한이 사실상 없는 거나 마찬가지라, ACK 프레임 1개 안에 무려 256개의 이빨 빠진 블록 구간을 리스트로 쫙 뽑아서 송신자에게 완벽한 손실 리포트를 쏴줄 수 있다.
- 덕분에 아무리 해저 케이블에서 패킷이 걸레짝처럼 듬성듬성 유실되어도, 단 한 번의 피드백만으로 모든 빵꾸를 0.1초 만에 싹 다 메워(재전송)버리는 미친 회복력을 보여준다.
📢 섹션 요약 비유: QUIC의 고유 패킷 번호 제도는, 우체국이 반송된 편지를 다시 보낼 때 **"옛날 송장 스티커를 뜯어내고, 오늘 자 날짜가 찍힌 완전히 새로운 송장 바코드 스티커를 무조건 새로 붙여서 보내는 원칙"**입니다. 덕분에 우체국 시스템(네트워크 혼잡 제어)은 언제 배송을 시작한 박스인지 1초의 오차도 없이 추적과 통계(RTT)를 낼 수 있습니다.