사전 DNS 캐시
개념

DNS 캐시

gabury1고친 사람 github-actions[bot]

DNS 캐시는 한 번 찾은 서버 주소를 기억해 두었다가 같은 이름을 다시 물을 때 바로 돌려줍니다. 덕분에 이름으로 주소를 찾을 때마다 멀리 있는 서버까지 다녀오지 않아도 됩니다. 답마다 얼마 동안 기억해도 되는지가 함께 적혀 옵니다. 그 시간이 지나면 기억을 버리고 다시 묻습니다.

쉽고 빠른 이해

무슨 일을 하나 — 이름으로 찾은 서버 주소를 잠시 기억해 둡니다. 브라우저가 shop.example.com 의 주소를 한 번 찾았다면 한동안은 다시 묻지 않습니다. 기억해 둔 주소로 바로 접속합니다.

왜 이렇게 하나 — 이름으로 주소를 처음 찾으려면 인터넷 곳곳의 서버에 차례로 물어야 합니다. 요청마다 이 일을 되풀이하면 접속이 늦어집니다. 이름을 맡은 서버에도 질문이 쏟아집니다.

어떻게 도나

  1. 답에는 「몇 초 동안 믿어도 된다」는 유효 시간이 붙어 옵니다
  2. 브라우저와 운영체제, 대신 물어 주는 중간 서버가 저마다 이 답을 기억합니다
  3. 유효 시간이 지나면 기억을 버리고 다시 묻습니다

대가 — 서버 주소를 바꿔도 유효 시간이 끝날 때까지는 옛 주소로 가는 사용자가 남습니다. 「그런 이름은 없다」는 답도 기억됩니다. 이름을 새로 등록해도 한동안 없다는 답이 돌아올 수 있습니다.

상세

자주 시키는 중국집 번호를 매번 114 에 묻는 사람은 없습니다. 한 번 물어본 번호를 휴대폰에 저장해 둡니다. 다음부터는 저장된 번호로 바로 겁니다.

프로그램은 서버에 접속하기 전에 shop.example.com 같은 도메인 이름으로 숫자 주소를 찾아야 합니다. 이 숫자 주소가 IP 주소(Internet Protocol address, 인터넷 프로토콜 주소)입니다. 이름으로 주소를 찾아 주는 체계는 DNS(Domain Name System, 도메인 네임 시스템)입니다.

DNS 캐시는 이렇게 찾은 결과를 잠시 기억해 두는 일입니다. shop.example.com 의 주소가 203.0.113.10 이라는 답을 받았다면 이 짝을 적어 둡니다. 같은 이름으로 주소를 다시 찾을 때는 묻지 않고 적어 둔 주소를 꺼냅니다.

이 절은 주소를 처음 찾는 길이 왜 비싼지부터 봅니다. 그다음 캐시가 놓이는 곳, 답을 기억하는 시간, 「없다」는 답, 백엔드에서 겪는 일을 짚습니다.

주소를 처음 찾는 길

인터넷의 이름 전부를 들고 있는 서버는 없습니다. 이름은 점을 경계로 층이 나뉩니다. 층마다 맡는 서버가 따로 있습니다. shop.example.com 이면 com 을 맡은 서버 아래에 example.com 을 맡은 서버가 따로 있습니다.

이름을 맡아 최종 답을 쥐고 있는 서버를 권한 네임서버(authoritative name server)라고 합니다. example.com 의 주인이 자기 서버 주소를 등록해 두는 곳이 이 서버입니다. 여기서 나오는 답이 원본입니다. 캐시가 기억하는 것은 모두 이 답의 사본입니다.

맨 위층은 루트 네임서버가 맡습니다. 루트 네임서버는 com 같은 꼭대기 이름을 어느 서버가 맡는지 알려 줍니다. 이름으로 주소를 찾는 일은 모두 원래 여기서 출발합니다.

위에서부터 차례로 물어 내려가는 일은 재귀 리졸버(recursive resolver)가 맡습니다. 재귀 리졸버는 우리 대신 여러 서버를 돌며 답을 구해 오는 서버입니다. 회사 네트워크나 인터넷 회선 업체가 대개 하나씩 둡니다. 누구나 쓸 수 있는 공용 리졸버도 있습니다.

캐시가 하나도 없다면 재귀 리졸버는 이름 하나로 주소를 찾으려고 아래처럼 움직입니다.

sequenceDiagram
    participant R as 재귀 리졸버
    participant Root as 루트 네임서버
    participant C as com 네임서버
    participant E as example.com 권한 네임서버
    R->>Root: shop.example.com 주소는?
    Root-->>R: com 은 이 서버에 물어라
    R->>C: shop.example.com 주소는?
    C-->>R: example.com 은 이 서버에 물어라
    R->>E: shop.example.com 주소는?
    E-->>R: 203.0.113.10

이름 하나에 인터넷 너머의 서버와 세 번 왕복합니다. 왕복이 끝나기 전에는 접속을 시작하지도 못합니다. 모든 컴퓨터가 요청마다 이 길을 걸으면 루트 네임서버에 온 세상의 질문이 몰립니다. DNS 캐시는 이 왕복을 건너뛰려고 둡니다.

캐시가 놓이는 곳

이름으로 주소를 찾는 길 위에는 캐시가 여러 겹 놓입니다. 프로그램에 가까운 캐시에 답이 있으면 더 먼 캐시까지 묻지 않습니다. 겹마다 답을 나눠 쓰는 범위가 다릅니다.

캐시가 있는 곳 답을 나눠 쓰는 범위
프로그램 안 그 프로그램 하나. 브라우저나 일부 언어 런타임이 따로 둔다
운영체제 그 컴퓨터에서 도는 모든 프로그램. 운영체제에 따라 두지 않기도 한다
재귀 리졸버 그 리졸버를 쓰는 모든 컴퓨터

많게는 세 겹을 거치는 모습은 아래와 같습니다.

flowchart TD
    A["프로그램이 이름으로 주소를 찾는다"] --> B{"프로그램 안 캐시에 있나"}
    B -->|있다| Z["기억해 둔 주소로 접속"]
    B -->|없다| C{"운영체제 캐시에 있나"}
    C -->|있다| Z
    C -->|없다| D{"재귀 리졸버 캐시에 있나"}
    D -->|있다| Z
    D -->|없다| E["루트 네임서버부터 차례로 묻는다"]
    E --> Z

셋 가운데 재귀 리졸버의 캐시가 가장 넓게 쓰입니다. 한 사람이 물어 둔 답을 같은 리졸버를 쓰는 다른 사람이 받아 갑니다. 주소를 자주 찾는 이름일수록 누군가 이미 물어 두었을 가능성이 큽니다.

재귀 리졸버는 최종 답만 기억하지 않습니다. 중간에 받은 「com 은 이 서버에 물어라」도 기억합니다. 다음에 other.com 의 주소를 찾을 때는 루트 네임서버를 건너뛰고 com 네임서버에 바로 묻습니다.

답에 붙어 오는 유효 시간

DNS 의 답은 DNS 레코드 단위로 옵니다. 레코드는 「이 이름의 이 종류 값은 이것」을 적은 한 줄입니다. 레코드 한 줄을 글자로 옮기면 아래와 같습니다.

shop.example.com.  300  IN  A  203.0.113.10

왼쪽부터 이름, 유효 시간, 네트워크 종류, 레코드 종류, 값입니다. 레코드 종류 칸의 A 는 이름에 IP 주소를 짝짓는 종류입니다. 이런 레코드를 A 레코드라고 합니다.

두 번째 칸의 300 은 이 답을 300초, 곧 5분 동안 기억해도 된다는 뜻입니다. 이 유효 시간을 TTL(Time to Live, 살아 있을 시간)이라고 합니다.

TTL 은 이름의 주인이 권한 네임서버에 레코드를 등록할 때 정합니다. 캐시는 답을 받은 순간부터 TTL 을 깎아 내려갑니다. 0 이 되면 그 답을 버립니다.

재귀 리졸버가 기억해 둔 답을 내줄 때는 남은 시간만 적어 줍니다. 200초 전에 받은 300초짜리 답이면 100초라고 적습니다. 운영체제와 프로그램의 캐시는 재귀 리졸버에게서 이 남은 시간을 받아 기억합니다. 그래야 여러 겹의 캐시가 원본이 정한 시간보다 오래 들고 있지 않게 됩니다.

TTL 을 얼마로 잡을지는 두 가지를 맞바꾸는 일입니다. 오래 기억할수록 묻는 횟수가 줄어듭니다. 대신 주소를 바꿨을 때 새 주소가 늦게 퍼집니다.

TTL 이 길면 TTL 이 짧으면
다시 묻는 횟수 적다 많다
접속 전 기다림 캐시에서 바로 답하는 일이 잦다 리졸버까지 가는 일이 잦다
주소를 바꾼 뒤 옛 주소가 오래 남는다 새 주소가 금방 퍼진다

서버를 옮길 계획이면 TTL 을 미리 줄여 둡니다. 옛 TTL 이 하루였다면 줄인 값이 모든 캐시에 퍼지는 데도 하루가 걸립니다. 그 뒤에 주소를 바꾸면 짧은 TTL 덕분에 새 주소가 금방 퍼집니다.

DNS 로 요청을 여러 서버에 나누는 DNS 기반 라우팅도 짧은 TTL 에 기댑니다. 장애 난 서버를 답에서 빼도 캐시가 옛 답을 들고 있으면 요청이 계속 그 서버로 갑니다. 그래서 이런 이름은 TTL 을 짧게 잡습니다.

없다는 답의 캐시

없는 이름을 물으면 권한 네임서버는 「그런 이름은 없다」고 답합니다. 이 답의 이름이 NXDOMAIN(Non-Existent Domain, 없는 도메인)입니다.

캐시는 이 답도 기억합니다. 이것이 네거티브 캐싱(negative caching)입니다. 누가 없는 이름을 계속 물어도 권한 네임서버까지 매번 가지 않게 하려는 것입니다. 없다는 답에도 따로 유효 시간이 붙어 옵니다.

백엔드 개발자는 새 이름을 등록할 때 이 캐시를 만납니다. new.example.com 을 등록하기 전에 확인 삼아 한 번 접속해 봤다고 합시다. 그 뒤 레코드를 만들어도 기억된 「없다」가 사라질 때까지는 없다는 답을 받습니다.

캐시가 원본과 어긋날 때

캐시는 답을 빨리 주는 대신 원본과 어긋난 답을 줄 수 있습니다. 백엔드에서 이 어긋남은 다섯 가지 모습으로 드러납니다.

주소를 옮긴 뒤 옛 서버로 오는 요청 — 서버를 새 주소로 옮기면 레코드도 고칩니다. 그래도 TTL 이 남은 캐시는 옛 주소를 내줍니다. 그래서 옛 서버는 TTL 이 넉넉히 지날 때까지 켜 둡니다. TTL 보다 오래 답을 들고 있는 캐시도 일부 있기 때문입니다.

오래 붙잡은 연결 — 이름으로 주소를 찾는 일은 연결을 맺을 때 한 번만 합니다. 연결을 미리 여러 개 맺어 두고 돌려 쓰는 커넥션 풀은 그 연결을 오래 붙잡습니다. 데이터베이스가 다른 서버로 넘어가면 이름은 새 주소를 가리킵니다. 그래도 붙잡힌 연결은 TTL 과 상관없이 새로 맺기 전까지 옛 서버를 향합니다.

프로그램 안의 캐시 — 일부 언어 런타임은 운영체제와 별도로 프로세스 안에 답을 기억합니다. 레코드의 TTL 대신 자기 설정값으로 기억 시간을 정하는 런타임도 있습니다. 이런 프로세스는 운영체제 캐시를 비워도 옛 주소를 씁니다.

비울 수 없는 남의 캐시 — 내 컴퓨터의 운영체제 캐시나 브라우저 안의 캐시는 내가 비울 수 있습니다. 사용자들이 쓰는 재귀 리졸버의 캐시는 비울 방법이 없습니다. 주소를 바꾼 뒤에는 TTL 이 지나기를 기다려야 합니다.

캐시에 심은 거짓 답 — 공격자가 재귀 리졸버의 캐시에 가짜 답을 심을 수 있습니다. 그러면 그 리졸버를 쓰는 모든 사람이 TTL 동안 가짜 주소로 갑니다. 캐시를 이렇게 오염시키는 공격이 DNS 캐시 포이즈닝입니다.

관련 항목

DNS 캐시가 속하는 상위 분류

DNS · 캐싱 · 도메인 이름 · IP 주소

DNS 캐시가 기억하는 레코드와 답

DNS 레코드 · A 레코드 · AAAA 레코드 · CNAME · NS 레코드 · SOA 레코드 · NXDOMAIN

DNS 캐시를 두거나 답을 내주는 서버와 부품

재귀 리졸버 · 스텁 리졸버 · 리졸버 · 권한 네임서버 · 루트 네임서버 · 네임서버

DNS 캐시가 답을 버리는 시점을 정하는 규칙

TTL · 네거티브 캐싱 · 만료 · 캐시 무효화 · 신선도

DNS 캐시의 짧은 TTL 에 기대는 기법

DNS 기반 라우팅 · 페일오버 · CDN · 블루-그린 배포

DNS 캐시 밖에서 옛 주소를 붙잡는 연결과 설정

커넥션 풀 · 지속 연결 · keep-alive · hosts 파일

DNS 캐시가 원본과 어긋나서 나는 장애

DNS 전파 · 낡은 데이터 · 캐시 스탬피드 · 썬더링 허드

DNS 캐시를 노리는 공격과 막는 기술

DNS 캐시 포이즈닝 · DNS 스푸핑 · DNSSEC

DNS 캐시와 헷갈리는 다른 캐시

브라우저 캐시 · HTTP 캐시 · CPU 캐시 · 페이지 캐시 · 공유 캐시

다른 이름: DNS cache · DNS 캐싱