무효화
저장해 둔 사본을 더는 못 쓰게 만드는 일입니다. 원본이 바뀌었으니 곁에 둔 복사본도 끊는 것입니다. 끊고 나면 그 자리를 다시 읽을 때 원본까지 다녀와야 합니다.
상세
전화번호를 바꾸면 내 번호를 수첩에 적어 둔 사람들은 그 사실을 모른 채 옛 번호로 전화를 겁니다. 내가 한 사람씩 연락해 지우거나 가위표를 쳐 두게 해야 합니다. 누구 수첩에 적혀 있는지 모르면 그 번호는 그대로 남습니다.
무효화는 저장된 사본을 더는 못 쓰게 만드는 조작입니다. 방식은 둘로 갈립니다. RFC(Request for Comments) 9111 은 무효화가 주어진 URI(Uniform Resource Identifier, 통합 자원 식별자)와 일치하는 저장된 응답을 전부 제거하거나, 그것들을 무효로 표시해서 다음 요청에 대한 응답으로 보내지기 전에 반드시 검증을 거치게 하는 것이라고 적습니다. 그 자리를 다시 읽으려면 원본까지 다녀와야 합니다.
방아쇠는 사건입니다. 상태를 바꿀 가능성이 있는 요청이 지나가면, 그 요청이 건드린 자리에 남아 있던 사본은 사실과 어긋납니다. 사본에 붙여 둔 수명이 아직 남아 있어도 마찬가지입니다.
무효화는 전역으로 보장되지 않습니다. RFC 9111 은 상태를 바꾸는 요청이 자기가 지나간 캐시 안의 응답만 무효화한다고 적습니다. 그 요청이 지나지 않은 자리의 사본은 그대로 남습니다. 그래서 사본이 몇 벌이고 어디에 있는지를 아는 쪽이 없으면 무효화는 그 사본들에 닿지 못합니다.
배경
사본을 두는 이유는 원본까지 다녀오는 값이 비싸기 때문입니다. 그런데 원본은 계속 바뀝니다. 바뀌는 순간부터 사본은 사실과 다른 값을 들고 있습니다. 사본을 들고 있는 쪽은 그 사실을 모른 채 계속 그 값을 내줍니다.
첫 번째 답은 사본마다 수명을 정해 두는 것이었습니다. 정해 둔 시간이 지나면 그 값을 못 쓰게 하는 방식입니다. 그러면 원본이 바뀐 사실을 이미 아는 쪽이 있어도 수명이 다할 때까지는 낡은 값이 계속 나갑니다. 필요한 것은 시간을 재는 수단이 아니라 사건에 반응하는 수단이었습니다.
RFC 9111 은 PUT · POST · DELETE 같은 안전하지 않은 요청 메서드가 오리진 서버의 상태를 바꿀 가능성을 갖기 때문에, 중간에 놓인 캐시들이 저장된 응답을 무효화해서 내용을 최신으로 유지하도록 요구받는다고 적습니다. 사건이 났을 때 사본을 끊는 이 조작에 붙은 이름이 무효화입니다.
예시
무효화는 한 자리의 기법이 아닙니다. 규정으로 못 박힌 자리가 있고, 사람이 손으로 호출하는 자리가 있고, 서버가 사본 보유자에게 알리는 자리가 있습니다.
RFC 9111 의 무효화 규정
HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 규약) 캐시는 안전하지 않은 요청 메서드에 대한 응답으로 오류가 아닌 상태 코드를 받으면 대상 URI 를 반드시 무효화해야 합니다. 오류가 아닌 응답은 2xx 또는 3xx 상태 코드를 가진 것입니다. 안전성을 알 수 없는 메서드도 여기에 포함됩니다.
다른 URI 는 무효화할 수 있습니다. 반드시는 아닙니다. 특히 응답의 Location 과 Content-Location
헤더 필드에 URI 가 들어 있으면 그것들이 무효화 후보입니다. 다른 URI 는 이 문서가 명시하지 않은
방법으로 발견될 수도 있습니다.
막힌 자리가 하나 있습니다. 무효화될 URI 의 오리진이 대상 URI 의 오리진과 다르면 캐시는 이 조건에서 무효화를 일으키면 안 됩니다. RFC 9111 은 이것이 서비스 거부 공격을 막는 데 도움이 된다고 적습니다.
Cloudflare 의 퍼지
파일 하나를 지목하는 쪽이 먼저입니다. 대시보드의 Purge Cache 에서 Custom Purge 를 고르고 Purge by 항목을 URL 로 두면 URL 을 넣는 칸이 나옵니다. 퍼지된 리소스는 모든 데이터센터의 저장된 자산에서 즉시 제거됩니다. 그 자산에 대한 새 요청은 오리진 웹 서버에서 최신 버전을 받습니다. 받은 것은 그 요청을 처리한 Cloudflare 데이터센터의 CDN(Content Delivery Network, 콘텐츠 전송 네트워크) 캐시에 다시 담깁니다. URL 의 호스트 부분은 대소문자를 가리지 않습니다. 언제나 소문자로 바뀝니다. 경로 부분은 대소문자를 가립니다.
파일이 여럿이면 하나씩 URL 을 대는 대신 태그를 붙입니다. 오리진 웹 서버에서 콘텐츠에 Cache-Tag
HTTP 응답 헤더를 답니다.
Cache-Tag: tag1,tag2,tag3
태그가 여럿이면 쉼표로 나눕니다. Cloudflare 는 이 헤더의 태그를 캐시되는 콘텐츠와 묶어 둡니다. 특정 태그를 퍼지하면 그 태그가 붙은 콘텐츠 전부가 대시보드에서든 API(Application Programming Interface, 응용 프로그램 인터페이스) 호출로든 즉시 퍼지됩니다. Cloudflare 는 퍼지된 태그를 가진 콘텐츠에 캐시 미스를 강제합니다.
Redis 의 무효화 메시지
사본이 서버 밖에 있으면 서버가 알려 줘야 합니다. Redis 의 클라이언트 사이드 캐싱 지원은 tracking 이라 불립니다. 기본 모드에서 서버는 어떤 클라이언트가 어떤 키를 읽었는지 기억해 두고, 같은 키가 수정되면 무효화 메시지를 보냅니다.
sequenceDiagram
participant 클라이언트1
participant 서버
participant 클라이언트2
클라이언트1->>서버: CLIENT TRACKING on
클라이언트1->>서버: GET foo
Note over 서버: 클라이언트1이 foo 를 캐시했을 수 있음을 기억
클라이언트2->>서버: SET foo someothervalue
서버->>클라이언트1: invalidate "foo"
연결은 tracking 이 꺼진 채로 시작합니다. 켜면 서버는 그 연결이 사는 동안 클라이언트가 읽기 명령으로 요청한 키를 기억합니다. 그 키가 수정되면 그것을 캐시하고 있을 만한 tracking 클라이언트 전부에게 무효화 메시지가 갑니다. 무효화 메시지를 받은 클라이언트는 낡은 데이터를 내주지 않도록 해당 키를 지워야 합니다.
경계
시간이 지나 캐시가 항목을 버리는 것도 무효화인가. 아닙니다.
사본에 TTL(Time To Live, 수명)을 정해 두고 그 시간이 다하면 못 쓰게 하는 방식이 있습니다. 결과만 보면 무효화와 같습니다. 어느 쪽이든 그 자리를 다시 읽으면 원본까지 다녀오게 됩니다. 가르는 선은 결과가 아니라 누가 방아쇠를 당기느냐입니다.
RFC 9111 은 신선도와 무효화를 서로 다른 절에서 다룹니다. 신선도 절은 나이가 신선도 수명을 아직 넘지 않은 응답을 신선하다고 부르고, 넘은 것을 낡았다고 부릅니다. 명시적 만료 시각은 저장된 응답을 캐시가 더 이상 검증 없이 쓸 수 없게 되기를 오리진 서버가 의도한 시각입니다. 여기에는 사건이 없습니다. 시계만 있습니다. 다만 Redis 가 만료 시각 때문에 사라지는 키를 tracking 클라이언트에 알릴 때 보내는 것은 무효화 메시지입니다.
관련 항목
무효화가 걸치는 캐시 계층
캐싱 · 캐시 · HTTP · HTTP 캐시 · CDN · 클라이언트 사이드 캐싱 · 오리진 서버
무효화를 정의·구현하는 표준과 서비스
RFC 9111 · Cloudflare · Redis
방아쇠가 다른 이웃
무효화가 거치는 수단과 절차
퍼지 · 태그 · Cache-Tag · 무효화 메시지 · pub/sub · tracking · maxmemory · API · 검증
무효화를 촉발하는 HTTP 요청 조건
요청 메서드 · 안전하지 않은 메서드 · PUT · POST · DELETE · 상태 코드
무효화 대상을 가리키는 식별자
URI · Location · Content-Location
무효화에 얽힌 위험과 결과
다른 이름: invalidation · cache invalidation · 캐시 무효화