사전 TTL
용어함정

TTL

gabury1

TTL 은 데이터에 붙여 두는 수명 예산입니다. 예산이 0 에 닿으면 그 데이터를 버립니다. 그런데 무엇이 그 예산을 깎는지는 쓰는 자리마다 다릅니다.

상세

TTL(Time to Live, 살아 있을 시간)은 세 자리에서 서로 다르게 정의됩니다. 세 정의가 공유하는 뼈대는 하나입니다. 데이터에 예산을 하나 붙여 두고, 예산이 0 에 닿으면 그 데이터를 버립니다. 갈리는 자리는 셋입니다. 무엇이 예산을 깎나, 단위가 무엇인가, 0 에 닿았을 때 무엇이 버려지나입니다.

IP(Internet Protocol, 인터넷 프로토콜)에서 예산을 깎는 것은 데이터그램을 처리하는 쪽입니다. RFC(Request for Comments, 의견 요청) 791 은 이 필드를 데이터그램이 인터넷 시스템에 머무를 수 있는 최대 시간이라 적고 단위를 초라고 적습니다. 그러면서 곧바로 단서를 답니다. 데이터그램을 1초 안에 처리하더라도 처리하는 모든 모듈이 TTL 을 최소 1 은 깎아야 하므로, TTL 은 데이터그램이 존재할 수 있는 시간의 상한으로만 생각해야 한다는 것입니다. RFC 1812 는 이 사정을 한 문장으로 못 박습니다. 그런 경우가 매우 잦으므로 TTL 은 사실상 데이터그램이 인터넷을 얼마나 멀리 퍼져 나갈 수 있는지를 정하는 홉 카운트 한도라고 적습니다.

DNS(Domain Name System, 도메인 이름 체계)에서 예산을 깎는 것은 시계입니다. RFC 1035 는 TTL 을 리소스 레코드를 캐시해 둬도 되는 시간 간격이라 적습니다. 단위는 초입니다. 그 간격이 지나면 캐시는 사본을 버리고 정보의 출처에 다시 물어봅니다.

키-값 캐시에서도 예산을 깎는 것은 시계입니다. 버려지는 대상이 다릅니다. Redis 문서는 EXPIRE 로 건 타임아웃이 지나면 그 키가 자동으로 삭제된다고 적습니다. 사본을 얼마나 들고 있어도 되는지가 아니라 원본을 언제 지울지를 적는 자리입니다.

어느 뜻이 원래 뜻인지는 이 문서들이 적지 않습니다. 그래서 TTL 이라는 말만으로는 무엇이 얼마나 남았는지가 정해지지 않습니다. 맥락 이름을 먼저 대야 뜻이 섭니다.

맥락별 뜻

맥락 뜻 출처
IP 데이터그램이 인터넷 시스템에 머무를 수 있는 최대 시간을 담은 8비트 필드. 처리하는 모듈마다 최소 1 을 깎으므로 사실상 홉 카운트 한도 RFC 791 3.1 · 3.2 · RFC 1812 5.3.1
DNS 리소스 레코드를 정보의 출처에 다시 물어보기 전까지 캐시해 둬도 되는 초 단위 시간 간격. 최대 수명이지 의무 수명이 아니다 RFC 1035 3.2.1 · 4.1.3 · RFC 2181 8
키-값 캐시 만료가 걸린 키에 남은 수명. 초 단위이고, 다 지나면 키 자체가 삭제된다 Redis TTL 명령 · EXPIRE 명령 문서

IP

RFC 791 은 값이 0 이면 데이터그램을 파기해야 한다고 적습니다. 이 필드는 인터넷 헤더를 처리하는 지점마다 데이터그램 처리에 쓴 시간을 반영해 줄여야 합니다. 실제로 쓴 시간을 알 수 있는 지역 정보가 없더라도 1 은 반드시 깎아야 합니다. 값 1 이 1초를 뜻하므로 최대 수명은 255초, 곧 4.25분입니다.

RFC 1812 는 라우터가 지켜야 할 것을 나눠 적습니다. 패킷을 다루는 라우터는 경과 시간이 1초에 한참 못 미치더라도 TTL 을 최소 1 은 깎아야 합니다. 패킷을 1초 넘게 들고 있으면 1초마다 1 씩 더 깎아도 됩니다. TTL 이 0 이하로 줄면 패킷을 버려야 하고, 목적지가 멀티캐스트 주소가 아니라면 출발지로 ICMP(Internet Control Message Protocol, 인터넷 제어 메시지 프로토콜) Time Exceeded 메시지를 Code 0 으로 보내야 합니다.

flowchart TD
    A["라우터가 패킷을 받는다"] --> B["TTL 을 최소 1 깎는다"]
    B --> C{"TTL 이 0 이하인가"}
    C -->|아니다| D["다음 홉으로 전달"]
    C -->|그렇다| E["패킷을 버린다"]
    E --> F["출발지로 ICMP Time Exceeded Code 0"]

경로 위의 다른 라우터가 TTL 을 0 으로 깎으리라 예측된다는 이유만으로 0 이 아닌 TTL 을 가진 유니캐스트나 브로드캐스트 패킷을 버려서는 안 됩니다. 다만 IP 멀티캐스트에는 그렇게 해도 됩니다. 멀티캐스트의 확장 링 탐색 알고리즘을 더 효율적으로 구현하기 위해서입니다.

DNS

RFC 1035 는 전송 형태의 TTL 을 32비트 부호 없는 정수로 적습니다. 리소스 레코드를 버리기 전까지 캐시해 둬도 되는 시간 간격이고 단위는 초입니다. 최상위 형식을 정의하는 자리에서는 같은 필드를 32비트 부호 있는 정수로 적으면서, 정보의 출처에 다시 물어보기 전까지 캐시해도 되는 간격이라고 풀어 씁니다.

sequenceDiagram
    participant 캐시
    participant 출처
    캐시->>출처: 리소스 레코드를 묻는다
    출처-->>캐시: 레코드와 TTL
    Note over 캐시: TTL 이 적은 간격 동안 사본을 쓴다
    캐시->>출처: 간격이 지나면 다시 묻는다

값이 0 이면 진행 중인 트랜잭션에만 쓸 수 있고 캐시해서는 안 된다는 뜻입니다. SOA 레코드(Start of Authority, 권한 시작)는 캐시를 막으려고 언제나 TTL 0 으로 배포됩니다. 극도로 자주 바뀌는 데이터에도 0 을 쓸 수 있습니다.

RFC 2181 은 앞선 정의가 유효 비트 수와 부호 여부에서 분명하지 않았다고 적고 값을 다시 정합니다. TTL 은 부호 없는 수이고 최소 0, 최대 2147483647 입니다. 전송할 때는 32비트 필드의 하위 31비트에 넣고 최상위 부호 비트를 0 으로 둡니다. 최상위 비트가 켜진 채 받은 값은 받은 값 전체가 0 인 것처럼 다루는 것이 좋습니다. 그리고 구현은 받은 TTL 에 언제나 상한을 둘 수 있고, 그보다 큰 값은 그 상한인 것처럼 다뤄도 됩니다. RFC 2181 은 그 이유를 한 문장으로 적습니다. TTL 은 최대 수명을 적는 것이지 의무 수명을 적는 것이 아니라는 것입니다.

키-값 캐시

Redis 의 TTL 명령은 타임아웃이 걸린 키의 남은 수명을 돌려줍니다. 클라이언트가 주어진 키를 앞으로 몇 초 더 데이터셋에서 볼 수 있는지 들여다보는 수단입니다. 키가 없으면 -2 를 돌려줍니다. 키가 있어도 걸린 만료가 없으면 -1 을 돌려줍니다. Redis 2.6 이하에서는 두 경우 모두 -1 이었습니다. 밀리초 해상도로 같은 정보를 얻는 명령은 PTTL 입니다.

수명을 거는 쪽은 EXPIRE 입니다. 타임아웃이 지나면 그 키는 자동으로 삭제됩니다. 타임아웃이 걸린 키를 Redis 용어로는 volatile 하다고 부릅니다.

  • 타임아웃을 지우는 것은 키의 내용을 지우거나 덮어쓰는 명령뿐입니다. DEL · SET · GETSET 과 모든 *STORE 명령이 여기 듭니다
  • INCR 로 값을 올리거나 LPUSH 로 리스트에 값을 넣거나 HSET 으로 해시 필드를 바꾸는 것처럼, 값을 새 것으로 갈아 끼우지 않고 바꾸기만 하는 연산은 타임아웃을 건드리지 않습니다
  • PERSIST 는 타임아웃을 지워 키를 다시 영구 키로 되돌립니다
  • RENAME 으로 키 이름을 바꾸면 남은 수명이 새 이름으로 함께 옮겨갑니다
  • EXPIRE 에 양수가 아닌 값을 주거나 EXPIREAT 에 과거 시각을 주면 키는 만료되는 것이 아니라 삭제됩니다. 그때 발행되는 키 이벤트도 expired 가 아니라 del 입니다

배경

같은 말이 세 자리에 붙어 있습니다. 이름과 실물이 어긋난 자리는 IP 하나입니다. RFC 791 이 이 필드를 둔 의도는 배달할 수 없는 데이터그램을 버려지게 하고 데이터그램의 최대 수명을 묶는 것이었습니다. 상위의 신뢰성 있는 연결 프로토콜 가운데는 일정 시간이 지나면 오래된 중복 데이터그램이 도착하지 않는다는 가정 위에 선 것들이 있습니다. TTL 은 그런 프로토콜이 자기 가정이 지켜진다는 보증을 얻는 수단이라고 791 은 적습니다.

시간을 재려면 각 모듈이 처리에 쓴 시간을 알아야 합니다. 그런데 791 은 그 시간을 알 수 없더라도 1 은 깎으라고 정했고, 그래서 실제로 세어지는 것은 시간이 아니라 처리한 모듈의 수가 됐습니다. RFC 1812 의 논의 절은 이 이중성을 그대로 적습니다. IP 의 TTL 은 홉 카운트 한도이면서 시간 한도로 쓰이고 있습니다. 홉 카운트 기능은 라우팅 문제가 패킷을 무한히 돌게 만들어 네트워크를 녹여 버리는 일을 막는 데 결정적입니다. 시간 한도 기능은 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 같은 전송 프로토콜이 신뢰성 있는 데이터 전송을 보장하려고 씁니다. 1812 는 많은 구현이 TTL 을 순수한 홉 카운트로 다루고 있고, 시간 한도 기능은 그것이 필요한 전송 프로토콜이 대신 수행해야 한다는 정서가 인터넷 커뮤니티 일부에 강하다고 적습니다. 그래서 라우터 벤더들의 강한 믿음을 마지못해 따라 시간 한도 기능을 선택 사항으로 두기로 했다고 적습니다.

이름을 실물 쪽에 맞춘 것이 IPv6(Internet Protocol version 6, 인터넷 프로토콜 6판) 입니다. RFC 8200 은 IPv6 노드가 최대 패킷 수명을 강제할 의무가 없다고 적고, 그것이 IPv4(Internet Protocol version 4, 인터넷 프로토콜 4판) 의 Time-to-Live 필드를 Hop Limit 으로 개명한 이유라고 적습니다. 실제로 패킷 수명을 제한하라는 요구를 지키는 IPv4 구현은 있다 하더라도 극히 적어서 실무에서 달라지는 것은 없다고 덧붙입니다. Hop Limit 필드는 패킷을 전달하는 노드마다 1 씩 줄어드는 8비트 부호 없는 정수입니다. 인터넷 계층에 기대어 패킷 수명을 제한하던 상위 프로토콜은 낡은 패킷을 스스로 찾아 버리는 수단을 갖추도록 개선되는 것이 마땅하다고 8200 은 적습니다. 반면 DNS 와 키-값 캐시 쪽에서는 이름과 실물이 어긋나지 않습니다. 시계가 초를 깎습니다.

경계

HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 의 Cache-Control: max-age 도 TTL 인가. 이 표제어의 맥락 표에는 올리지 않습니다. 하는 일은 DNS 의 TTL 과 같습니다. RFC 9111 은 max-age 응답 지시자를 delta-seconds 를 인자로 받는 지시자로 정의하고, 응답의 나이가 그 초 수를 넘으면 응답을 신선하지 않은 것으로 본다고 적습니다. 그런데 명세는 이 자리에 TTL 이라는 이름을 쓰지 않습니다. 맥락별 뜻의 한 줄은 맥락과 뜻과 출처 세 칸이 다 서야 성립합니다. 출처가 그 이름을 쓰지 않으니 줄이 서지 않습니다. 명세의 어휘와 실무의 어휘가 갈리는 자리입니다.

같은 문서가 잡아 주는 차이가 하나 더 있습니다. 신선도를 상대 기간으로 적느냐 절대 시각으로 적느냐입니다. max-age 는 초 수를 세는 상대 기간입니다. Expires 헤더 필드는 그 시각 이후로 응답을 신선하지 않은 것으로 보게 하는 날짜와 시각, 곧 HTTP-date 타임스탬프입니다. 응답에 max-age 지시자가 있으면 받는 쪽은 Expires 헤더 필드를 무시해야 합니다. 공유 캐시라면 s-maxage 지시자가 있을 때도 마찬가지입니다. Expires 의 값은 Cache-Control 헤더 필드를 아직 구현하지 않은 수신자만 쓰라고 둔 것이라고 RFC 9111 은 적습니다. TTL 이라는 이름이 붙는 세 맥락은 모두 상대 기간 쪽입니다.

관련 항목

TTL을 정의하는 표준·문서

RFC 791 · RFC 1812 · RFC 1035 · RFC 2181 · RFC 9111 · RFC 8200

TTL 뜻이 갈리는 프로토콜·시스템

IP · DNS · Redis

IP에서 TTL이 실려 가는 경로

데이터그램 · 라우터 · 노드

TTL의 두 기능이 지키는 대상

라우팅 · 네트워크 · TCP

TTL이 다 닳으면 나가는 오류 신호

ICMP · Time Exceeded · 메시지

TTL 0 처리가 갈리는 주소 종류

유니캐스트 · 브로드캐스트 · 멀티캐스트

TTL이 맥락마다 갖는 다른 표현

IPv4 · IPv6 · Hop Limit · 홉 카운트 · 타임아웃

DNS에서 TTL이 캐시하는 대상과 예외

리소스 레코드 · SOA 레코드 · 트랜잭션

TTL을 다루는 Redis 명령

EXPIRE · PTTL · PERSIST · RENAME · EXPIREAT

TTL을 대신하는 HTTP의 캐시 신선도 장치

HTTP · max-age · Expires · s-maxage · Cache-Control · delta-seconds · HTTP-date · 신선도 · 공유 캐시

다른 이름: Time to Live · Time-to-Live