행성간 QUIC 트래픽을 향해

ko생성일: 2025. 11. 18.갱신일: 2025. 11. 19.

심우주 환경에서 QUIC을 신뢰성 있게 동작시키기 위한 구성과 실험 방법을 소개합니다. 느리고 간헐적인 링크를 고려한 맞춤 설정, 즉시 실행 가능한 시뮬레이션 워크벤치, 재현 가능한 테스트와 디버깅 기법에 대해 다룹니다.

퍼서비어런스(Perseverance) 화성 탐사 로버에서 지구로 사진을 내려받을 때 어떤 프로토콜이 쓰이는지 스스로에게 물어본 적이 있나요? 저도 2024년 4월 인터넷에서 흥미로운 메시지를 보기 전까지는 그런 생각을 해본 적이 없었습니다.

심우주 IP 프로젝트를 위해 quic/quinn에 밝은 분을 찾고 있습니다. 파트타임 컨설팅 형태가 될 겁니다. 관심 있으시면 DM 주세요.

메시지 자체는 짧고 전문 용어도 조금 있어 몇 번을 읽고 나서야 프로젝트가 무엇인지 온전히 이해할 수 있었습니다.

  • QUIC와 함께 작업: 신뢰성 있는 통신을 위한 인터넷 프로토콜(즉, 보통 TCP가 맡는 역할).
  • Quinn과 함께 작업: Rust에서 가장 널리 쓰이는 QUIC 구현체.
  • QUIC을 사용해 지구와 아주 멀리 떨어진 컴퓨터(예: 다른 행성) 사이를 통신.

당시 제 일도 잘 풀리고 있었고, 다른 컨설팅에 할애할 시간은 많지 않았지만… 행성간 인터넷 프로젝트를 어떻게 거절하겠습니까? 예전에 Quinn에 기여한 적도 있었고1, 도움이 될 준비가 되어 있다고 느껴 직접 참여하기로 했습니다. 이 글은 지금까지의 모험을 기록한 것입니다.

무엇을 해결하려는가?

심우주는 광활하고 도전으로 가득합니다. 그런 환경에서 네트워크를 운영하는 것 자체가 기적에 가깝습니다. 어느 정도는 문제가 해결된 상태이기도 합니다. 인류는 정기적으로 화성 로버와 메시지를 주고받고, 심지어 태양계를 벗어난 우주선과도 통신하고 있죠2. 하지만 우주 탐사에 더 많은 플레이어가参入할수록, 현재 아키텍처의 한계가 뚜렷해지고 있습니다3.

심우주 네트워킹을 확장하려는 노력은 계속되고 있으며, 그 유망한 대안 중 하나는 IP 프로토콜 제품군을 채택하는 것입니다. 그런 맥락에서, 신뢰성 있는 통신을 위한 프로토콜로 QUIC을 선택하려 합니다. 바로 여기서 이 프로젝트가 등장합니다. 우리의 목표는 QUIC이 심우주에서 신뢰성 있게 동작할 수 있음을 보이고, 이를 배포하려는 이들을 위한 지침을 제공하는 것입니다.

QUIC과 심우주

“QUIC이 심우주에서도 신뢰성 있게 동작함을 보인다”는 말이 왜 그리도 중요할까요? 그냥 바로 가져다 쓰면 안 될까요?

알고 보니 심우주 통신은 꽤… 복잡합니다. 우선 지연이 엄청납니다. 예컨대 지구에서 보낸 메시지가 화성에 도달하는 데 3분에서 23분이나 걸립니다4. 게다가 연결은 간헐적입니다. 예를 들어 지구와 화성 로버 사이에 무선 신호를 주고받을 수 없는 시간이 자주 있으며, 일정 시간이 지나야 다시 연결이 복구됩니다5.

이런 조건에서는 QUIC이 기본 설정으로는 동작하지 않습니다. 일단 연결 수립을 시도해도 성공하기 전에 타임아웃이 나 버립니다. 그런데 문제는 더 깊습니다. 설령 마법처럼 연결을 수립한다 해도, 다른 문제들이 연이어 발생해 금세 연결을 죽여버릴 겁니다6.

그렇다면 QUIC은 어떻게 유효할 수 있을까요? 눈치 빠른 독자라면 이미 답을 짐작했을 겁니다. 문제는 QUIC 자체가 아니라, 지상 인터넷을 전제로 설계된 _기본 설정_입니다. 우리가 필요한 것은 심우주를 겨냥한 _맞춤 설정_이며, 각 우주 임무가 필요에 따라 추가로 조정할 수 있는 가이드라인입니다7.

맞습니다. QUIC은 매우 높은 수준으로 구성 가능합니다. 이는 엄청난 장점입니다. 필요한 QUIC 구성 스위치만 노출되어 있다면, 표준을 준수하는 구현체를 수정 없이 심우주 환경에서 그대로 실행할 수 있기 때문입니다. 멋지죠!

그렇다면 오래된 노장 TCP는 어떨까요? 사실 2000년대 초반에 평가가 이뤄졌지만, 해당 프로토콜은 심우주에 부적합하다는 결론이 내려졌습니다8.

QUIC 실험 수행하기

좋습니다. 심우주에서도 QUIC이 효율적으로 동작하게 하는 구성을 찾아야 합니다. 실제로는 어떻게 하면 될까요?

먼저 필요한 맥락을 조금 공유하겠습니다. “QUIC 구성”이란, 프로토콜의 내부 동작을 좌우하는 매개변수 집합을 말합니다. 예컨대 패킷을 주고받기 전 초기 왕복 지연시간(RTT) 추정치는 얼마인가? 비활성으로 인해 연결이 끊겼다고 판단하기까지 얼마나 기다릴 것인가? 어떤 혼잡 제어 메커니즘을 사용할 것인가? 대략 이런 것들이죠.

펜과 종이, 계산기를 들고, 아마도 동작할 것 같은 값들을 도출할 수는 있습니다. 하지만 “어떤 계획도 적과의 첫 접촉을 견디지 못한다”는 사실을 우리는 너무나 잘 압니다. 실제로 매개변수가 작동하는 모습을 보고, 정말로 효과가 있는지 경험적으로 확인해야 합니다. 그래서 실험을 하자는 아이디어가 나온 겁니다.

실험이란 QUIC을 원하는 매개변수로 구성한 다음, 심우주 조건을 모사한 네트워크를 통해 데이터를 주고받는 것입니다. 이렇게 하면 관련 지표를 수집하고, 매개변수 선택을 평가하고, 필요에 따라 다른 값을 시도해 보면서, 무엇이 통하고 무엇이 통하지 않는지를 점차 탄탄히 이해할 수 있습니다.

실험 셋업, 첫 번째 시도

우리의 실험 셋업은 두 구성요소를 가진 프로그램으로 이뤄져 있습니다. QUIC 연결을 통해 파일을 제공하는 서버 애플리케이션, 그리고 그 파일을 내려받는 클라이언트 애플리케이션입니다. 둘은 테스트 네트워크로 연결됩니다.

제가 프로젝트에 합류했을 때의 테스트 네트워크는 여러 대의 가상 머신으로 구성되어 있었고, 심우주 네트워크의 관련 하위 집합(예: NASA 연구원의 노트북과 화성 로버가 통신할 때 관련되는 노드들)을 정교하게 재현하고 있었습니다. 실제 노드 구성을 반영했을 뿐 아니라, 심우주 조건에 맞춘 인위적 지연과 간헐성까지 포함되어 있었죠! 매우 영리한 셋업이고, 지금도 계속 사용하고 있습니다.

다만 한 가지 작은 문제가 있습니다. 아마 이미 떠올리셨을지도 모르겠네요. 네트워크에 실제 심우주 지연을 도입하는 순간, 실험을 수행하는 데 엄청난 시간이 걸립니다. 화성 로버에서 파일을 내려받는 테스트를 하고 싶나요? 그럼 커피 한 잔 내려오세요. 화성 왕복 지연시간(RTT)은 최대 46분까지 갈 수 있거든요. 게다가 간헐성이 있으면 더 오래 걸린다는 말, 이미 했던가요? 그렇습니다. 반복 속도가 악몽입니다.

즉시 실행되는 실험을 가능하게 하기

이 느린 반복 속도를 보고 저는 개인적 도전으로 받아들였습니다. “내 눈앞에서 그런 일은 없을 거야!” 제 속마음의 전투 함성이었죠. 저는 즉각적인 피드백이 생산적인 연구를 위한 필수 조건이라고 믿습니다. 단지 있으면 좋은 게 아니죠.

제 가설은 두 가지를 통제하면 즉시 실행이 가능하다는 것이었습니다.

  1. 시계(Clock). 애플리케이션의 시계가 정상보다 훨씬 빠르게 진행되어야 합니다. 이상적으로는, 프로세스가 타이머 만료를 기다리느라 블록될 때마다 시간이 그만큼 “점프”하면 됩니다. 제대로 구현된다면 시작부터 끝까지의 소요 시간은 컴퓨터 성능에만 좌우될 것입니다.
  2. 패킷 IO. 시간이 점프하더라도, 네트워크에서 패킷을 읽을 때는 여전히 기다려야 합니다. 그러면 진행을 막는 것은 타이머(시간 점프를 유발)가 아니라 IO(실제 기다림 필요)가 됩니다. 해결책은? 패킷 IO를 없애는 것입니다! 대신 클라이언트와 서버를 하나의 프로세스 안에서 실행하고, 그 사이를 시뮬레이션된 네트워크(역시 그 프로세스 안에서 실행)로 통신시키면 됩니다. 이 인프로세스 네트워크는 우리가 직접 작성하고 제어하므로, 링크 지연을 애플리케이션의 시계에 종속시킬 수 있습니다. 따라서 프로그램의 다른 지연과 마찬가지로 건너뛰어질 수 있죠.

혹시 묻고 싶을 겁니다. 시계와 하부 네트워크를 제어하게 해주는 QUIC 구현체가 있나요? 음… Quinn이 그렇습니다! 이 라이브러리의 설계는 믿기지 않을 정도로 모듈화되어 있고, 필요한 확장 지점을 제공합니다.

예를 들어, 시간 점프는 구현이 아주 쉬웠습니다. Quinn은 시간 측정을 async 런타임에 위임하는데, 우리가 사용하는 런타임(tokio)에는 우리가 필요한 방식 그대로 시계를 자동으로 진행시키는 기능이 있습니다. Builder::start_paused를 켰더니 그대로 “그냥 작동”했습니다9.

인프로세스 네트워크로 전환하는 일은 더 손이 갔습니다. 애초에 네트워크 시뮬레이션을 처음부터 작성해야 했기 때문이죠. 저는 물고 늘어졌고 결국 해냈습니다. 그리고 시뮬레이션된 네트워크를 AsyncUdpSocketUdpPoller 트레이트를 통해 Quinn에 연결했습니다.

그 노력이 보람이 있었냐고요? 물론입니다! 이제 우리는 QUIC으로 파일 다운로드를 순식간에 실행할 수 있습니다… 게다가 빠르다는 것 말고도 추가 선물까지 얻었습니다. 참고로 중요한 테스트 케이스의 추가 검증을 위해 예전 셋업도 계속 유지하고 있습니다.

보너스: 결정성과 디버깅 용이성

네트워크를 완전히 제어할 수 있게 되자, 워크벤치를 완전히 결정적으로 만들 수 있었습니다. 예전 셋업과 달리, 이제 같은 매개변수로 두 번 실행하면 항상 같은 출력이 나옵니다. 이는 재현 가능한 실험에 필수적이며, 지금까지 엄청난 도움이 되었습니다(“내 컴퓨터에서는 되는데…” 같은 상황이 일어날 여지가 없습니다).

디버깅 용이성도 챙겼습니다. 패킷이 인프로세스 네트워크를 통과할 때, 각 피어는 나중에 검사할 수 있도록 합성된 .pcap 파일에 패킷을 기록합니다. 그렇게 하면 Wireshark 같은 외부 도구로 문제를 트러블슈팅하거나, 단순히 시뮬레이션된 선로를 타고 무엇이 전송되는지 관찰할 수 있습니다. 이 작은 투자는 충분히 값어치를 했습니다. 그렇지 않으면 까만 상자일 대상을 엑스레이처럼 들여다보게 해주거든요. 디버깅이 쉬운 시스템이 최고입니다!

마무리

그럼… 퍼서비어런스 화성 로버에서 지구로 사진을 내려받을 때 어떤 프로토콜이 쓰일까요? 지금은 CFDP라는 저수준 프로토콜이라고 들었습니다… 당장은요. 아마 몇 년 후에는 답이 QUIC이 될지도 모릅니다!

ACKnowledgements(감사의 말)

제 작업은 Marc Blanchet 없이는 불가능했을 겁니다. 그는 심우주에서의 IP를 열정적으로 옹호해 왔습니다. 프로젝트에 아낌없이 자금을 지원해 주었고, 제 질문에 무한한 인내심으로 답해 주었으며, 이 글의 초기 초안도 검토해 주었습니다. 또한 제가 만든 실험 셋업을 오픈소스로 공개하고자 하여, 누구나 실험을 해볼 수 있도록 했습니다. 저장소는 여기에서 찾을 수 있습니다.

또한 Quinn 커뮤니티에도 경의를 표합니다. 특히 라이브러리 작성자인 BenjaminDirkjan에게요. 그들은 뛰어난 API를 설계했을 뿐 아니라, 커뮤니티의 다른 분들과 함께 우리가 겪은 문제들에 대해 유용한 조언을 건네주었습니다. Rust 생태계에서 QUIC 라이브러리를 찾고 있다면, Quinn이 가장 좋은 선택이라고 말씀드리고 싶습니다.


  1. 2023년에 저는 Stormshield를 위해 두 달간 계약을 맺고 Quinn에 여러 기능을 넣었습니다(그해의 제 PR들을 참고하세요).↩︎

  2. 아직 It’s quieter in the twilight을 보지 않았다면, 즐거운 시간이 될 겁니다.↩︎

  3. 우주 커뮤니티의 외부인인 제 입장에서 현재 네트워킹 아키텍처의 한계를 설명하는 것은 역부족입니다. 다행히 이 RFC 초안의 도입부가 좋은 설명을 제공합니다.↩︎

  4. 지연 범위가 넓은 이유는 화성이 때로 지구에 가깝기도(약 3광분) 하고, 때로는 태양의 반대편(약 23광분)에 있기 때문입니다.↩︎

  5. 간헐성은 주로 궤도선을 행성 표면과의 통신 중계로 쓰기 때문입니다. 궤도선은 행성을 공전하며, “볼 수 있는” 피어와만 통신할 수 있습니다. 이로 인해 목적지 가시성이 회복될 때까지 IP 패킷을 저장해 두었다가 전달해야 합니다. 또한 화성 태양 합 현상처럼, 일주일 넘게 통신이 중단되는 드문 간헐성 이벤트도 있습니다. 자세한 내용은 이 기사를 참고하세요.↩︎

  6. 예를 들어 간헐성은 왕복 지연시간의 큰 도약을 유발합니다(예: 6분에서 24시간으로). 일반적인 상황에서라면 QUIC 피어는 연결이 끊겼다고 결론 내릴 것입니다.↩︎

  7. 이 초안은 현재 연구 상태를 요약합니다.↩︎

  8. 예: Why not use the Standard Internet Suite for the Interplanetary Internet?.↩︎

  9. 이후 저는 커스텀 sans-IO async 런타임도 만들었습니다. tokio의 타이머가 밀리초 단위로 동작해, 시뮬레이션 결과의 신뢰도를 떨어뜨릴 수 있다고 우려했기 때문입니다. 결국 런타임을 바꿔도 의미 있는 차이는 없었지만, 만드는 동안 정말 즐거웠습니다.↩︎