rust

4 개의 포스트

ecdysis를 통한 오래된 코드 탈 (새 탭에서 열림)

Cloudflare는 수년간 자사 인프라에서 수백만 건의 요청을 중단 없이 처리하며 검증한 Rust 라이브러리 'ecdysis'를 오픈소스로 공개했습니다. 이 라이브러리는 네트워크 서비스 업데이트 시 연결 끊김이나 새로운 연결 거부 없이 프로세스를 재시작할 수 있는 '우아한 재시작(Graceful Restart)' 기능을 제공합니다. 이를 통해 보안 패치나 기능 업데이트 시에도 실시간 트래픽에 영향을 주지 않고 안전하게 최신 코드로 교체할 수 있습니다. ### 기존 재시작 방식의 한계와 문제점 * 단순한 재시작 방식(이전 프로세스 종료 후 새 프로세스 시작)은 소켓을 닫는 순간부터 새 프로세스가 리스닝을 시작할 때까지 공백이 발생하며, 이 기간에 들어오는 연결은 커널에 의해 `ECONNREFUSED`로 거부됩니다. * 이미 연결된 세션(대용량 업로드, 비디오 스트리밍, WebSocket 등)이 프로세스 종료와 함께 강제로 끊기며 사용자 경험에 악영향을 미칩니다. * `SO_REUSEPORT` 옵션은 여러 프로세스가 동일한 포트를 바인딩하게 해주지만, 새 프로세스가 연결을 수락(`accept`)하기 전에 이전 프로세스가 종료되면 커널 큐에서 대기 중이던 연결들이 고아 상태가 되어 폐기되는 고유의 결함이 있습니다. ### ecdysis의 작동 원리와 포크 모델 * NGINX의 설계 방식을 차용하여, 실행 중인 부모 프로세스가 `fork()`를 통해 자식 프로세스를 생성하고, 자식은 `execve()`를 실행하여 새 버전의 코드로 자신을 교체합니다. * 이 과정에서 부모 프로세스는 명명된 파이프(named pipe)를 통해 소켓 파일 디스크립터(FD)를 자식에게 상속하며, 두 프로세스가 잠시 소켓을 공유하여 공백 없는 트래픽 처리를 보장합니다. * 자식 프로세스가 초기화를 완료했다는 신호를 보내면 부모는 그제야 소켓을 닫고 기존 연결만 처리한 뒤 종료(Draining)되며, 만약 자식이 초기화 중 충돌하더라도 부모가 여전히 동작 중이므로 서비스 중단이 발생하지 않습니다. ### 주요 기능 및 시스템 통합 * **Tokio 비동기 런타임 지원**: 고성능 Rust 서비스를 위해 Tokio용 비동기 스트림 래퍼를 기본 제공하므로, 상속받은 소켓을 별도의 복잡한 연동 없이 즉시 리스너로 사용할 수 있습니다. * **systemd 통합**: `systemd-notify` 기능을 내장하여 서비스 유닛 설정의 `Type=notify-reload`와 연동될 수 있으며, 시스템 레벨에서 프로세스 수명 주기를 정확히 추적할 수 있습니다. * **검증된 신뢰성**: Cloudflare의 글로벌 네트워크에서 트래픽 라우팅, TLS 수명 주기 관리, 방화벽 규칙 적용 등 가장 핵심적인 서비스들에 5년 넘게 사용되며 안정성을 입증했습니다. 가용성이 극도로 중요한 Rust 기반 네트워크 서비스를 운영한다면, `ecdysis`는 복잡한 소켓 공유 로직을 직접 구현할 필요 없이 제로 다운타임 업데이트를 구현할 수 있는 가장 실무적인 해결책이 될 것입니다.

대규모 환경의 Rust (새 탭에서 열림)

WhatsApp은 최근 30억 명 이상의 사용자들을 멀웨어 위협으로부터 보호하기 위해 미디어 처리 라이브러리를 Rust 언어로 재구축하여 성공적으로 배포했습니다. 이는 글로벌 규모의 서비스에서 Rust가 프로덕션 환경에 적합함을 증명한 사례로, 특히 메모리 안전성이 취약한 C/C++ 기반의 미디어 파싱 라이브러리에서 발생할 수 있는 보안 취약점을 근본적으로 해결하는 데 중점을 두었습니다. 결과적으로 WhatsApp은 성능과 메모리 효율성을 동시에 개선하면서도 사용자 보안을 한층 더 강화하는 성과를 거두었습니다. **미디어 보안의 취약점과 대응의 역사** - 이미지나 영상처럼 무해해 보이는 파일도 운영체제의 취약점을 공격하는 악성 코드를 포함할 수 있으며, 2015년 안드로이드의 'Stagefright' 취약점이 대표적인 사례입니다. - 당시 WhatsApp은 OS 라이브러리의 패치를 기다리는 대신, 자체 개발한 C++ 기반의 미디어 일관성 검사 라이브러리인 'wamedia'를 통해 표준을 준수하지 않는 파일을 사전에 차단하는 방식을 택했습니다. - 하지만 미디어 체크 로직 자체가 신뢰할 수 없는 입력을 자동으로 처리하기 때문에, 이 라이브러리 자체의 메모리 안전성을 확보하는 것이 보안의 핵심 과제로 떠올랐습니다. **Rust를 통한 대규모 현대화 및 성능 개선** - WhatsApp은 점진적인 수정 대신 기존 C++ 버전과 병행하여 Rust 버전의 라이브러리를 새롭게 개발했습니다. - 두 언어 간의 호환성을 보장하기 위해 '디퍼런셜 퍼징(Differential Fuzzing)'과 광범위한 통합 테스트를 거쳐 안전성을 검증했습니다. - 기존 160,000줄의 C++ 코드를 90,000줄의 Rust 코드로 대체했으며, 결과적으로 이전보다 더 우수한 성능과 낮은 런타임 메모리 사용량을 기록했습니다. - 안드로이드, iOS, 웹, 웨어러블 등 다양한 플랫폼 지원을 위한 빌드 시스템 구축과 바이너리 크기 최적화라는 기술적 난관을 극복하고 글로벌 배포를 완료했습니다. **다층 방어 체계 'Kaleidoscope'의 구축** - Rust로 작성된 이 라이브러리들은 'Kaleidoscope'라 불리는 종합 보안 체크 시스템의 핵심 구성 요소입니다. - 단순히 파일 구조의 결함을 찾는 것을 넘어, PDF 내의 스크립트 요소나 임베디드 파일, 확장자를 위조한 MIME 타입 변조 등을 감지합니다. - 실행 파일이나 앱 설치 파일과 같은 위험한 파일 형식을 식별하여 사용자 인터페이스(UX) 차원에서 특별 관리함으로써 비공식 클라이언트나 악성 첨부파일로부터 사용자를 보호합니다. **메모리 안전 언어 중심의 보안 로드맵** - WhatsApp의 분석에 따르면 심각도가 높은 취약점의 대부분은 C/C++의 메모리 관리 문제에서 발생하며, 이를 해결하기 위해 새로운 코드 작성 시 메모리 안전 언어(Memory Safe Language)를 기본으로 선택하고 있습니다. - 불필요한 공격 표면을 최소화하고, 기존 C/C++ 코드에 대해서는 강화된 메모리 할당자와 보안 버퍼 API를 적용하는 등 보안 보증 투자를 병행하고 있습니다. - 이번 Rust 도입의 성공을 바탕으로 향후 더 많은 영역에 Rust 채택을 가속화하여 내부 방어 체계를 지속적으로 강화할 계획입니다. **결론 및 제언** WhatsApp의 사례는 보안이 중요한 클라이언트 사이드 애플리케이션에서 Rust가 단순한 대안을 넘어 최고의 선택지가 될 수 있음을 보여줍니다. 특히 외부에서 유입되는 미가공 데이터를 파싱해야 하는 시스템이라면, 메모리 안전성이 보장되는 Rust로의 전환을 통해 보안 사고의 근본 원인을 제거하고 운영 효율성을 높이는 전략을 적극 검토할 필요가 있습니다.

CNAME이 먼저인가 A 레 (새 탭에서 열림)

Cloudflare의 DNS 서비스인 1.1.1.1은 메모리 사용량을 최적화하기 위해 DNS 응답 내 레코드 순서를 변경했다가 전 세계적인 접속 장애를 일으켰습니다. 대다수 현대 소프트웨어는 DNS 레코드 순서를 무시하지만, glibc와 같은 특정 구현체는 CNAME 레코드가 A 레코드보다 먼저 등장할 것을 전제로 작동하기 때문입니다. 결국 Cloudflare는 이전의 순서로 로직을 롤백하여 문제를 해결했습니다. ### CNAME 체인과 부분 캐싱 메커니즘 * **DNS 별칭 추적:** `www.example.com`을 조회할 때 리졸버는 최종 IP 주소에 도달할 때까지 여러 개의 CNAME(별칭)을 따라가며, 이 과정에서 발생하는 모든 중간 레코드를 캐싱합니다. * **부분 만료 처리:** 체인 내 레코드들은 각기 다른 TTL(유효 기간)을 가집니다. 일부 CNAME은 유효하지만 최종 A 레코드가 만료된 경우, 리졸버는 전체 체인을 다시 조회하는 대신 만료된 부분만 갱신하여 기존 캐시와 병합합니다. * **병합 과정의 중요성:** 갱신된 레코드와 기존 캐시 레코드를 하나의 응답으로 합칠 때, 이들의 배열 순서가 클라이언트의 해석 방식에 영향을 미칩니다. ### 성능 최적화를 위한 로직 변경 * **기존 방식 (CNAME 우선):** 새로운 리스트를 생성하여 캐시된 CNAME들을 먼저 넣고, 그 뒤에 새로 조회된 A 레코드를 추가했습니다. 이는 메모리 할당과 복사 비용이 추가로 발생합니다. * **변경 방식 (A 레코드 우선):** 메모리 사용량을 줄이기 위해 기존의 응답 리스트 끝에 CNAME 레코드를 단순히 덧붙이는(append) 방식으로 변경했습니다. * **결과:** 이 사소한 변경으로 인해 DNS 응답 데이터에서 CNAME이 최종 결과값인 A 레코드보다 뒤에 위치하게 되었습니다. ### glibc 등 DNS 클라이언트의 처리 방식 문제 * **순차적 탐색:** 리눅스에서 널리 사용되는 `glibc`의 `getaddrinfo`와 같은 구현체는 DNS 응답을 순차적으로 읽으며 '찾아야 할 이름'을 업데이트합니다. * **인식 실패:** 클라이언트가 CNAME을 먼저 발견하면 "다음 타겟 이름"을 갱신하고 이후에 나오는 A 레코드를 수락합니다. 하지만 A 레코드가 먼저 나오면 아직 CNAME 정보를 모르기 때문에 해당 레코드를 무관한 데이터로 간주하고 무시합니다. * **결과적 오류:** 모든 데이터를 읽었음에도 불구하고 클라이언트는 매칭되는 IP를 찾지 못해 최종적으로 응답이 비어 있다는 결론을 내리게 됩니다. ### 시사점 및 결론 40년 된 DNS 프로토콜의 모호성으로 인해 레코드 순서에 대한 엄격한 정의가 부족할 수 있지만, 실제 환경에서는 전통적인 순서(CNAME -> Answer)를 유지하는 것이 하위 호환성을 위해 필수적입니다. 시스템의 성능 최적화가 기존 생태계의 암묵적인 동작 원리를 깨뜨리지 않는지, 특히 표준 라이브러리 수준의 하위 호환성을 철저히 검증해야 함을 보여주는 사례입니다.

피그마가 게임 세계에서 (새 탭에서 열림)

피그마는 단순한 웹 애플리케이션을 넘어 고성능 게임 엔진과 유사한 기술적 아키텍처를 기반으로 구축된 창의적 협업 도구입니다. 이 글은 피그마가 실시간 멀티플레이어 시스템, 물리 기반 애니메이션, 그리고 C++와 WebAssembly, Rust와 같은 고성능 스택을 통해 어떻게 디지털 세계를 구축하는지 설명합니다. 결과적으로 피그마는 게임 개발의 복잡한 시스템 상호작용 원리를 차용하여 사용자들에게 몰입감 있고 매끄러운 디자인 경험을 제공하고 있습니다. ## 디지털 세계를 구축하는 엔진으로서의 피그마 * 피그마의 핵심은 웹 기반의 2D 그래픽 및 렌더링 시스템으로, 이는 마인크래프트와 같은 게임 엔진의 근간과 동일한 구조를 가집니다. * 사용자가 생성하는 모든 텍스트, 도형, 선을 브라우저에서 실시간으로 구현하며, 방대한 캔버스에서의 팬(pan)과 줌(zoom) 조작 시에도 정확한 위치에 객체를 렌더링합니다. * 실시간 동시 편집 기능을 게임의 개념에서 착안한 '멀티플레이어(multiplayer)' 엔진이라고 명명하여 협업의 핵심 시스템으로 발전시켰습니다. * 브라우저 및 모바일 앱의 메모리와 성능 제약을 극복하기 위해 일반적인 웹 스택 대신 C++로 캔버스를 구축한 후 WebAssembly로 컴파일하여 로딩 속도를 3배 개선했으며, 서버 측 성능 향상을 위해 Rust 언어를 도입했습니다. ## 시스템 기반의 창의적 협업과 상호작용 * 게임 스튜디오에서 엔지니어와 아티스트가 협업하듯, 피그마 엔지니어들은 시스템의 한계를 밀어붙이기 위해 디자이너, PM, 데이터 과학자들과 긴밀하게 소통합니다. * '젤다의 전설: 브레스 오브 더 와일드'의 불(fire) 시스템이 빛, 온기, 공격 수단 등 다양한 방식으로 상호작용하는 것처럼, 피그마의 오토세이브, 멀티플레이어, 렌더링 시스템도 서로 유기적으로 연결되어 작동합니다. * 단순한 도구 기능을 넘어 스프링 물리 법칙을 적용한 애니메이션 시스템, 커서 채팅, 하이파이브 기능 등을 통해 사용자가 도구 내에서 살아있는 피드백을 느낄 수 있도록 설계했습니다. * 베리언트(Variants) 기능과 플러그인/위젯 시스템을 통해 디자인 컴포넌트와 코드를 긴밀하게 연결하고, 사용자가 직접 생태계를 확장할 수 있는 개방형 플랫폼을 지향합니다. 웹 환경에서 복잡하고 성능 집약적인 도구를 개발해야 한다면, 전통적인 웹 프레임워크의 틀을 벗어나 게임 엔진의 설계 방식과 고성능 언어(WASM, Rust) 도입을 검토해야 합니다. 기술적 한계를 극복하는 열쇠는 도구를 하나의 살아있는 '시스템'들의 집합으로 바라보고, 각 요소 간의 상호작용이 사용자 경험에 미치는 영향을 정교하게 설계하는 데 있습니다.