DNS 캐시에서 100TB를 덜어낸 다섯 단계: Rust 메모리 배치의 실제 비용
Cloudflare가 1.1.1.1 DNS 캐시의 항목당 메모리를 953바이트에서 420바이트로 줄였다. Vec 용량, enum 크기, 힙 할당과 캐시 지역성이 운영 성능으로 이어지는 과정을 살펴본다.
Cloudflare가 2026년 8월 27일 공개한 1.1.1.1 DNS 캐시 최적화 결과는 작은 자료구조 선택이 대규모 서비스에서 얼마나 큰 비용이 되는지 보여준다. 다섯 차례의 변경으로 캐시 항목 하나의 순수 메모리 사용량은 953바이트에서 420바이트로 56% 줄었다. 전체 운영 환경에서는 약 100TB의 작업 메모리가 비었고, 삽입 처리량은 43% 늘었으며 조회 지연은 19% 낮아졌다.
무엇이 바뀌었나
대상은 Rust로 작성된 재귀 DNS 리졸버 ‘Big Pineapple’의 메모리 캐시다. 캐시 키는 질의 이름·유형·클래스 등을 식별하고, 값에는 DNS 응답의 answer·authority·additional 구역과 생성 시각, 적중 횟수, TTL1 같은 정보가 들어간다. Cloudflare는 이 구조에서 저장 뒤에는 필요하지 않은 여유 용량과 반복 데이터를 차례로 없앴다.
- Vec를 Box 슬라이스로 전환: 삽입 뒤 길이가 바뀌지 않는 목록에서 capacity 필드를 제거했다. Rust의
Vec는 포인터·길이·용량을 가지지만Box<[T]>는 포인터와 길이만 필요하다. - 세 구역을 하나의 목록으로 통합: answer·authority·additional을 각각 보관하던 목록을 한 목록과 두 개의 2바이트 오프셋으로 바꿔 항목당 28바이트를 줄였다.
- 반복되는 owner 이름 생략: 레코드 소유자 이름이 질의 도메인과 같으면 별도 저장하지 않고 읽을 때 추론했다. 다른 이름만 선택적으로 힙에 보관했다.
- 큰 enum 변형을 Box로 분리: 가장 큰 변형에 맞춰 전체 enum 크기가 커지는 문제를 줄였지만, 별도 힙 할당과 포인터 추적 비용이 남았다.
- 레코드 데이터를 wire format으로 저장: 최종적으로 레코드 데이터만 연속된 바이트 버퍼에 넣어 enum과 개별 Box 할당을 없앴다. 조회 시 대부분의 레코드를 다시 필드별 직렬화하지 않고 응답 버퍼로 복사할 수 있게 됐다.
개발자에게 왜 중요한가
자료구조의 명목상 크기만 줄인다고 실제 프로세스 메모리가 같은 비율로 줄지는 않는다. 할당기는 크기 등급에 맞춰 공간을 반올림하고, Rust는 정렬을 위해 패딩을 넣는다. 작은 Box를 많이 만들면 포인터와 할당 메타데이터가 늘고 데이터가 힙 곳곳에 흩어져 CPU 캐시 지역성도 나빠질 수 있다. 이번 사례에서 큰 enum 변형을 Box로 옮긴 중간 단계보다 연속 바이트 버퍼가 메모리와 조회 성능을 함께 개선한 이유다.
측정 방식도 주목할 만하다. Cloudflare는 실제 트래픽 분포를 근사한 임의 항목으로 캐시를 채우고 Rust의 std::alloc::GlobalAlloc을 감싼 추적 할당기로 항목당 비용을 비교했다. 이어 5월 18일부터 7월 6일까지 단계적으로 배포하면서 운영 인스턴스의 상주 메모리를 확인했다. p99 메모리는 9.3GB에서 5.3GB로 43%, p90은 6.5GB에서 3.8GB로 42% 줄었다. 벤치마크의 56%보다 운영 감소폭이 작은 것은 프로세스에 캐시 외 데이터도 포함되기 때문이다.
기존 프로젝트에 미치는 영향
이번 변경은 Cloudflare의 내부 구현 사례이며 일반 애플리케이션이 설치할 새 버전이나 보안 패치는 아니다. 따라서 즉시 마이그레이션할 대상은 없다. 다만 메모리에 동일한 형태의 객체를 수백만 개 보관하는 캐시·인덱스·메시지 처리기는 같은 점검 순서를 적용할 수 있다. 특히 저장 후 불변인 Vec, 반복 문자열, 가장 큰 변형 때문에 부풀어 오른 enum, 짧은 객체마다 생기는 힙 할당은 프로파일링 후보가 된다.
적용 전 확인 사항
- 실제 분포로 측정: 평균 객체만 보지 말고 크기와 유형의 운영 분포를 반영한다.
- 순수 할당량과 RSS를 분리: 자료구조 단위 벤치마크 뒤 실제 프로세스의 상주 메모리와 지연을 함께 측정한다.
- 무작위 접근 요구 확인: 연속 wire format은 압축과 복사에는 유리하지만 임의 레코드 접근은 순차 순회를 요구할 수 있다.
- 읽기·쓰기 균형 검증: 직렬화 비용을 삽입 시점으로 옮기거나 재사용 버퍼를 둘 때 핫 패스가 실제로 빨라지는지 확인한다.
- 점진 배포: 캐시가 다시 차오르는 구간의 일시적 하락을 안정 상태의 개선으로 오인하지 않도록 충분한 관찰 기간을 둔다.
Cloudflare는 확보한 메모리를 캐시 용량 확대에 다시 투입해 적중률을 높이고 상위 DNS 질의를 줄일 계획이라고 밝혔다. 공개된 수치는 특정 구현과 트래픽에서 나온 결과이므로 다른 서비스에 그대로 대입할 수는 없다. 하지만 ‘필드 몇 바이트’가 아니라 할당·정렬·지역성·직렬화까지 함께 측정해야 한다는 원칙은 넓게 적용된다.
출처
- Cloudflare Blog — How we saved 100 terabytes of memory by optimizing 1.1.1.1’s DNS cache (2026년 8월 27일)
- Rust 표준 라이브러리 — Vec 문서
- Rust 표준 라이브러리 — Slice 문서
- RFC 1035 — Domain Names: Implementation and Specification
1 TTL(Time to Live): DNS 응답을 다시 조회하기 전까지 캐시에 보관할 수 있는 유효 시간.