[WarpInfra] WASM을 버리고 네이티브 QUIC로 갈아탄 날
한때 전송 코어는 WASM에 얹혀 있었다. 웹과 데스크톱이 같은 코어를 쓰려는 의도였다. 코드 한 벌로 두 환경을 커버하는 건 매력적인 목표고, 처음에 그 선택을 비웃을 이유는 없었다. 그런데 데스크톱 — 이 제품의 본무대 — 에서 그 선택이 오히려 발목을 잡았다. 이 편은 WASM 의존을 제거하고 네이티브 QUIC로 전환한 커밋들을 추적하며, "공용 코어"라는 이상이 무엇을 대가로 유지되는지를 본다.
그때의 실패 세 가지
WASM 전송 경로는 데스크톱에서 세 가지로 무너졌다. 각각은 독립적인 문제지만, 공통점이 있다 — 전부 "기능이 없는" 것이 아니라 "운영할 수 없는" 부류의 문제라는 점이다.
첫째, 성능. 대용량 청크 처리에서 네이티브 대비 오버헤드가 컸다. 파일 전송은 GB 단위 데이터를 청크로 쪼개 끊임없이 흘려보내는 작업이라, 경계 하나를 넘을 때마다 복사·변환 비용이 반복된다. 전송 코어는 데이터를 다루는 코드이기 전에 데이터를 이동시키는 코드고, 이동 비용이 구조적으로 붙는 경로는 재능으로 극복되지 않는다.
둘째, 오류 표면. WASM 경계에서 에러가 뭉개져서 원인 추적이 어려웠다. 호스트(데스크톱)와 게스트(WASM) 사이를 오가는 에러는 경계에서 정보가 잘린다. 네이티브였다면 스택 트레이스가 끝까지 잡아줬을 실패가, 경계를 넘는 순간 "전송 실패"라는 한 줄로 압축된다. 전송 시스템의 운영은 실패의 원인을 아는 데서 시작하는데, 그 첫 단추가 경계 구조에서 빠져 있었다.
셋째, 상태 제어. 연결 상태를 세밀하게 관리하기 어려웠다. 커밋 9253ddb의 제목이 이 문제의 결론을 그대로 담고 있다 — "quic-peer-connected 이벤트 시 연결 상태 설정". 즉 연결 상태가 이벤트 주도로만 전이되도록 고쳤다. quic-peer-connected가 오면 상태가 바뀌고, 그 전엔 어떤 UI도 "연결됨"을 그리지 않는다. 상태를 추측이 아니라 사건으로만 정의하는 규율이다. 이 규율이 필요해진 이유도 경계 구조 — 상태의 진실이 두 세계에 나뉘어 있으면 둘 중 하나는 틀린다.
전환을 결정한 판단의 순서
이 세 가지 실패를 나열하면 "그럼 처음부터 네이티브 하지"라고 생각하기 쉽다. 하지만 WASM 선택은 당시 정보로는 합리적이었다. 웹이 제품의 공개 얼굴이었고, 데스크톱은 그 뒤를 따라가는 형태로 상정돼 있었다. 코어를 웹에 맞추면 데스크톱은 자동으로 따라온다는 계산 — 결과적으로 이 계산이 틀렸고, 틀린 지점은 데스크톱이 "후발 주자"가 아니라 본무대라는 것. 이 편의 전환은 사실 제품의 무게중심이 어디인지를 다시 확인하는 과정이었다.
전환을 미루는 변명도 얼마든지 있었다. 성능 오버헤드는 청크 크기를 키우면 어느 정도 흡수된다. 오류 뭉개짐은 경계에 로깅을 보강하면 완화된다. 상태 제어는 우회하는 이벤트 목록을 만들면 된다. 각각은 가능하고, 전부 하면 WASM이 겨우 "쓸 만"해진다. 그런데 그 세 가지 완화책의 유지보수 비용을 매년 내면서 얻는 것이 "웹과 같은 코어"라는 정신적 만족뿐이라면, 트레이드오프는 명확하다. 전환 결정의 실질적 트리거는 이 계산이었다.
전환 커밋
| 커밋 | 내용 |
|---|---|
8aabffc | 네이티브 전송 시스템으로 전환, WASM 의존성 제거 |
accb3ca | WAN 연결성 구현, QUIC 기반 다중 파일 전송 |
9fb1894 | QUIC 연결 처리 및 오류 관리 개선 |
9253ddb | quic-peer-connected 이벤트 시 연결 상태 설정 |
c6f0928 | 고성능 스트리밍 전송 아키텍처 |
커밋 순서를 보면 전환이 한 번에 끝난 게 아니다. 8aabffc가 방향을 틀었고, accb3ca에서 WAN 연결성과 다중 파일이 뒤따랐고, 9fb1894·9253ddb에서 오류와 상태 처리가 정리됐고, c6f0928에서 스트리밍 아키텍처로 마무리됐다. 전환 커밋 하나가 화려하지, 그 뒤를 따르는 정리 커밋들이 실제 전환의 본체다. 방향 전환의 비용은 전환 커밋이 아니라 그 뒤의 꼬리에서 청구된다 — 새 경로에서 반드시 다시 발생할 오류 처리와 상태 관리의 재구축.
9253ddb를 다시 보자. 이 커밋이 고친 것은 기능이 아니라 계약이다. "연결됨"의 정의를 내부 변수가 아니라 외부 사건으로 바꿨다. 이벤트 주도 상태 전이의 부작용도 있다 — 이벤트가 오지 않으면 상태가 안 바뀐다는 것. 즉 이벤트 발생의 신뢰성이 곧 상태 표시의 신뢰성이 된다. 그래서 이벤트 발생 지점의 커버리지가 중요해지고, 놓친 이벤트에 대한 타임아웃 정책이 뒤따라야 한다. 간결해 보이는 규율 뒤에 이런 청구서가 붙는다.
전환 이후 달라진 것과 그대로인 것
전환이 실제로 무엇을 바꿨는지 항목별로 정리하면 다음과 같다.
성능 면에서, 경계를 넘는 복사·변환 비용이 사라지고 스트리밍 파이프라인(c6f0928)이 청크를 소유권 이동으로 처리할 수 있게 됐다. 오류 면에서, 네이티브 스택 트레이스가 끝까지 잡히면서 9fb1894 같은 오류 관리 개선이 가능해졌다 — WASM 경계에서는 원인 추적이 안 되니 개선할 대상조차 특정할 수 없었다. 상태 면에서, 9253ddb의 이벤트 주도 상태 전이가 단일 세계 안에서 일관되게 적용됐다.
그대로인 것도 분명히 하자. 전송의 알고리즘적 골격 — piece 분할, 해시 검증, 재개 논리 — 은 WASM 시절의 설계가 그대로 이어졌다. 버려진 것은 실행 환경이지 설계가 아니다. 이 구분이 중요한 이유는, 전환 작업을 "다시 짜기"로 오해하면 검증도 전부 다시 해야 한다고 착각하기 때문이다. 실제로는 골격이 같으므로 검증 항목의 상당 부분이 재사용됐다. 전환의 공수가 과하지 않았던 이유 중 하나다.
또 하나 기록해 둘 것은 WAN 연결성(accb3ca)이 전환 커밋 바로 뒤에 온다는 점이다. WASM 시절에는 어차피 데스크톱 성능 한계가 병목이라 WAN 환경의 네트워크 특성까지 논할 단계가 아니었다. 네이티브로 바뀌자 네트워크가 새로운 병목이 됐고, 다중 파일 전송과 WAN 대응이 다음 과제로 떠올랐다. 병목을 제거하면 다음 병목이 드러난다 — 지극히 예측 가능한 순서지만, 미리 순서를 알고 있으면 전환 직후의 작업 큐를 미리 준비할 수 있다.
설계 결정
| 대안 | 채택? | 이유 |
|---|---|---|
| WASM 공용 코어 유지 | ❌ | 성능·오류·상태 제어 삼중 실패 |
| 네이티브 QUIC 전송 | ✅ | 데스크톱 본무대, 스트리밍·멀티파일 |
기각의 대가도 명확히 쳐야 한다. WASM 공용 코어의 가장 큰 가치는 "웹과 같은 코드"였다. 네이티브로 가면 웹 쪽은 자기 수송체(WebRTC)를 별도로 갖게 되고, 두 경로의 로직 중복이 생긴다. 이 비용은 그리드 레포 분리로 구조화됐다 — 웹 세계를 별도 엔진으로 빼되, 두 엔진이 공유하는 개념(manifest, piece, 무결성)을 도메인 언어로 정렬시키는 방식. 완전한 해법은 아니지만 "코드 공유"라는 낭만적 목표를 버리고 "개념 공유"라는 실현 가능한 목표로 낮춘 것이라 할 수 있다.
QUIC을 수송체로 택한 이유는 별도의 논쟁 없이 좁혀졌다. 데스크톱은 소켓을 열 수 있고, 스트리밍 전송·연결 마이그레이션·오류 복구가 프로토콜 수준에 있다. 파일 전송 제품에 필요한 것들의 대부분이 이미 프로토콜 안에 있으니, 우리는 전송 정책과 piece 스케줄링에 집중하면 된다.
이때의 비교 대안도 기록해 둔다. TCP + 자체 재개 로직, 또는 HTTP 기반 청크 다운로드도 가능한 길이었다. 두 대안 모두 전송 자체는 되지만, "연결이 바뀌어도 이어지는" 특성과 다중 스트림을 자체 코드로 재발명해야 한다. 재발명한 코드는 검증 부담을 그대로 가져온다. 프로토콜에 이미 있는 것을 쓰면 그 부분의 검증은 프로토콜 구현체의 책임이 된다. "우리가 검증해야 할 코드의 총량을 줄인다"는 관점으로 보면 QUIC 선택은 성능 문제 이전에 검증 경제학의 문제였다.
남은 구멍
네이티브 전환으로 성능은 확보했지만, 인증서 검증과 mTLS는 이때 미뤄졌다. "QUIC이 연결됐다"는 암호화 수송이지 신원 검증이 아니기 때문이다. 연결이 암호화돼 있다는 것과 연결 상대가 우리가 믿는 노드라는 것은 별개의 문제다. 전송 제품의 보안 경계는 후자에 있고, 그 장치는 아직 앞에 있다. 이 구멍은 S4 백로그에 명시적으로 남아 있고, RC1 원칙 3이 그 기준이다.
미루기를 선택한 것도 판단이었다. 인증서 체계는 PKI 설계 — 누가 발급하고, 어떻게 배포하고, 만료되면 어떻게 교체하는가 — 를 동반하는 별도의 전문 영역이다. 전송 경로 전환과 동시에 밀어붙이면 두 가지 큰 변경이 한꺼번에 검증돼야 해서 실패 원인이 섞인다. 한 번에 하나의 큰 변경만. 이 원칙에 따라 mTLS는 명시적으로 백로그로 넘겨졌고, 그래서 백로그에 "제거되지 않은 인증서 검증 우회"라는 문장으로 정직하게 기록돼 있다.
한 가지 기록으로 남길 것은, 이 전환이 "WASM은 나쁘다"는 결론이 아니라는 점이다. WASM은 웹 환경에서 여전히 유효한 선택지고, 그리드 엔진 쪽에서 다른 형태로 쓰일 수 있다. 무너진 것은 WASM이 아니라 "데스크톱 전송 코어를 WASM에 얹는" 배치였다. 전환의 교훈은 기술의 우열이 아니라 기술의 배치 — 어떤 환경이 제품의 본무대인가에 따라 코어가 살아야 할 자리가 달라진다는 것이다.
이 시리즈
- 이전: CLI를 1등 시민으로 둔 이유
- 다음: 폴더가 단일 스트림으로 줄줄이 나가던 버그
- 목차: PonsWarp 개발 회고