눈앞에 숨겨진 100테라바이트 문제
Cloudflare의 글로벌 DNS 인프라는 'Big Pineapple'이라는 적절한 이름의 플랫폼을 기반으로 놀라운 규모로 운영됩니다. 이 플랫폼은 전 세계 수많은 사용자를 위한 1.1.1.1, Gateway DNS, DNS Firewall과 같은 핵심 서비스를 뒷받침하며 2,500억 개 이상의 DNS 캐시 항목을 상시 관리합니다.
이러한 거대한 운영 규모에도 불구하고, Cloudflare 엔지니어들은 만연해 있던 숨겨진 비효율성을 발견했습니다. 953바이트로 벤치마킹된 일반적인 DNS 캐시 항목에는 DNS 데이터 자체가 아닌 내부 데이터 구조 관리를 위한 상당한 양의 '메모리 오버헤드'가 포함되어 있었습니다. 예를 들어, Rust의 기본 'Vec' 및 'String' 타입은 포인터, 길이, 용량 필드를 저장합니다.
데이터가 늘어나지 않는 정적 캐시 DNS 레코드의 경우, 이 용량 필드는 소중한 메모리를 낭비하는 불필요한 부담이 되었습니다. 이러한 사소해 보이는 비효율성은 방대한 네트워크 전체에서 극적으로 증폭되었습니다. 2,500억 개의 레코드에서 항목당 단 1바이트만 낭비되어도 250기가바이트가 넘는 불필요한 RAM이 낭비되는 셈입니다.
이처럼 광범위한 메모리 낭비는 서버 전체의 운영 비용과 맞먹었으며, 데이터 구조 설계에서 간과하기 쉬운 작은 세부 사항이 어떻게 거대한 인프라 비용으로 불어날 수 있는지를 보여주었습니다. Cloudflare의 발견은 Rust와 같은 고수준 언어에서도 세밀한 메모리 관리의 중요성을 강조했습니다.
용량 제거: Rust의 양날의 검
Rust의 데이터 구조는 종종 유연성을 우선시합니다. 'Vec' 및 'String'과 같은 표준 타입은 향후 확장을 위해 필요한 것보다 더 많은 메모리를 할당함으로써 동적 데이터를 효율적으로 관리합니다. 각 인스턴스는 데이터에 대한 포인터, 현재 길이, 그리고 미리 할당된 용량이라는 세 가지 정보를 암묵적으로 저장합니다.
이 전략은 변경 가능한 데이터에는 매우 효과적이지만, 변경 불가능한 레코드에는 순수한 낭비입니다. Cloudflare의 2,500억 개 DNS 캐시 항목은 한 번 저장되면 고정되어 확장되거나 축소되지 않습니다. 따라서 추가 용량 필드는 'Big Pineapple' 내에서 아무런 기능적 목적을 수행하지 않으면서도 귀중한 시스템 자원만 소비했습니다.
이러한 비효율성을 인식한 엔지니어들은 'Vec'과 'String'을 'boxed slices'('Box<[T]>')와 'boxed strings'('Box<str>')로 교체했습니다. 이러한 특수 Rust 타입은 데이터에 필요한 정확한 메모리만 할당하여 용량 필드를 완전히 제거했습니다. 이 사소해 보이는 변화로 개별 캐시 항목당 64바이트를 절약했습니다.
Cloudflare의 방대한 글로벌 인프라 전반에 걸쳐 이 최적화는 즉시 15TB 이상의 RAM을 확보했습니다. 이는 데이터 구조 의미론에 대한 깊은 이해와 애플리케이션의 특정 요구 사항을 결합할 때 어떻게 엄청난 효율성 향상을 이끌어내고, 잠자고 있던 메모리를 활성 자원으로 전환할 수 있는지를 보여줍니다.
박스를 넘어: 데이터 패킹의 기술
Cloudflare는 answer, authority, additional과 같은 DNS 섹션에 대해 개별 포인터를 사용하는 방식을 넘어 'tightly packed' 데이터 전략을 채택했습니다. 이들은 이러한 섹션들을 하나의 연속된 메모리 블록으로 통합한 다음, 2바이트의 작은 오프셋을 사용하여 각 부분으로 정확하게 이동했습니다. 이를 통해 포인터 오버헤드를 제거했으며, 캐시 항목 크기를 953바이트에서 항목당 420바이트로 56% 줄이는 데 크게 기여했습니다.
추가적인 최적화는 캐시 내의 중복성과 구조적 비효율성을 해결하는 데 집중되었습니다. Cloudflare는 소유자 이름이 쿼리와 중복될 경우 이를 저장하지 않고, 필요할 때만 캐시 키에서 재구성하도록 변경했습니다. 가장 큰 변형을 기본값으로 사용하는 Rust enum 크기 문제를 해결하기 위해, NAPTR과 같이 크고 드문 레코드 유형에 대해 boxing을 구현했습니다. 이를 통해 A 및 AAAA와 같이 더 작고 일반적인 레코드가 차지하는 메모리를 크게 줄일 수 있었습니다.
마지막 주요 변경 사항은 레코드 데이터를 완전히 파싱된 Rust 구조체 대신 원시 길이 접두사가 붙은 wire-format bytes로 저장하는 것이었습니다. 이는 지속적인 파싱이 필요 없는 데이터에 대해 Rust의 풍부한 타입 시스템이 유발하는 메모리 오버헤드를 우회하여, Big Pineapple의 2,500억 개 캐시 항목 전체의 메모리 점유율을 더욱 줄였습니다. 이러한 독창적인 메모리 절약 기술에 대한 자세한 내용은 How we saved 100 terabytes of memory by optimizing 1.1.1.1's DNS cache | Cloudflare Blog에서 확인할 수 있습니다.
이 글이 마음에 드셨나요? 매일 아침 이런 글을 메일로 받아보세요.
하루 한 통 · 두 번의 클릭으로 구독 취소 · 제3자 추적 없음
성과: 더 빠르고 더 작게
세심한 데이터 재설계는 놀라운 결과로 이어졌습니다. Cloudflare는 일반적인 DNS 캐시 항목 크기를 953바이트에서 420바이트로 줄였습니다. 이는 항목당 메모리 점유율이 56% 감소했음을 의미합니다. 2,500억 개 이상의 캐시 항목을 관리하는 Cloudflare의 글로벌 인프라 전반에서, 이번 최적화를 통해 새로운 서버를 추가하지 않고도 무려 100테라바이트의 메모리를 확보했습니다.
중요한 점은 이러한 메모리 절약이 성능 저하를 동반하지 않았으며, 오히려 작업 속도가 크게 향상되었다는 것입니다. 캐시 삽입 속도는 초당 625,000개에서 893,000개로 43% 빨라졌습니다. 마찬가지로 조회 속도 또한 19% 개선되었으며, 지연 시간은 828나노초에서 670나노초로 단축되었습니다. 이 드문 '윈-윈' 시나리오는 기존의 트레이드오프를 극복하고 상당한 자원 효율성과 운영 속도 향상을 동시에 달성했습니다.
Cloudflare는 확보된 100테라바이트의 메모리를 전략적으로 활용하여 DNS 캐시 용량을 확장할 예정입니다. 더 크고 강력해진 캐시는 "Big Pineapple" 플랫폼이 더 많은 쿼리를 로컬에서 처리할 수 있게 합니다. 이는 업스트림 서버에서 데이터를 가져올 필요성을 직접적으로 줄여주며, 전 세계 사용자에게 더 빠른 DNS 확인 속도를 제공하고 모든 사람의 인터넷 속도를 눈에 띄게 향상시킵니다.
자주 묻는 질문
Cloudflare는 이번 최적화로 얼마나 많은 메모리를 절약했나요?
Cloudflare는 새로운 하드웨어를 추가하지 않고도 글로벌 인프라 전반에서 약 130대의 서버 메모리에 해당하는 약 100테라바이트(TB)의 RAM을 확보했습니다.
메모리 최적화로 인해 Cloudflare의 DNS 속도가 느려졌나요?
아니요, 오히려 정반대의 효과가 나타났습니다. 캐시 삽입 속도는 43%, 조회 속도는 19% 향상되었으며, 이는 메모리 사용량과 속도 사이의 일반적인 트레이드오프를 뒤집는 결과입니다.
Cloudflare는 이를 달성하기 위해 어떤 프로그래밍 언어를 사용했나요?
Cloudflare는 Rust 프로그래밍 언어를 사용했으며, 세밀한 메모리 제어 기능을 활용하여 DNS 캐시 항목의 구조를 재작성했습니다.
메모리를 절약하기 위해 Cloudflare가 취한 주요 변경 사항은 무엇인가요?
핵심 변경 사항은 Vec 및 String과 같은 표준 Rust 데이터 타입을 Box<[T]> 및 Box<str>로 교체한 것입니다. 이를 통해 크기가 변하지 않는 캐시 데이터에 대해 불필요했던 'capacity' 필드를 제거하여 항목당 64바이트를 절약했습니다.
Cloudflare는 어떻게 DNS 캐시 항목 크기를 56% 줄였나요?
그들은 capacity 필드 제거, 데이터 섹션을 오프셋과 함께 단일 블록으로 압축, 중복 정보 제거, 큰 enum 변형의 boxing, 그리고 데이터를 원시 wire format으로 저장하는 다섯 가지 핵심 Rust 수준의 변경 사항을 구현했습니다.

