공유 캐시
고친 사람 github-actions[bot]
공유 캐시는 한 번 받아 둔 복사본을 여럿이 함께 꺼내 쓰게 하는 캐시입니다. 앞사람이 받아 온 것을 뒷사람에게도 내주므로 원본까지 다녀오는 횟수가 줄어듭니다. 대신 한 사람에게만 가야 할 내용이 다음 사람에게 갈 수 있습니다. 그래서 무엇을 담아도 되는지 정하는 규칙이 따라붙습니다.
쉽고 빠른 이해
공유 캐시는 한 번 받아 온 것을 여럿에게 나눠 주는 저장소입니다. 누가 요청해도 같은 것이 나가는 공개 이미지는 한 번만 받아 두면 됩니다.
저마다 자기 캐시만 들고 있으면 같은 것을 찾는 사람이 몇이든 각자 첫 요청은 원본까지 갑니다. 캐시 하나를 여럿이 나눠 쓰면 그 왕복이 한 번으로 줄어듭니다. 서버마다 캐시를 따로 두면 같은 질문에 서버마다 다른 답이 나올 수 있습니다. 캐시 하나를 함께 보면 모든 서버가 같은 값을 봅니다.
- 요청이 공유 캐시를 먼저 지납니다
- 들고 있는 것이 아직 쓸 만하면 원본에 안 가고 그것을 내줍니다
- 없거나 낡았으면 원본에서 받아 옵니다. 담아도 되는 것이면 다음 사람 몫으로 남깁니다
대가는 남의 것을 내줄 위험입니다. 로그인한 사람의 화면처럼 사람마다 다른 응답이 담기면 다음 사람이 그 화면을 볼 수 있습니다. 잘못 담긴 것도 지나가는 모두에게 갑니다.
상세
회사 복도에 붙은 공용 공지판을 떠올려 봅니다. 한 장을 붙여 두면 지나가는 사람이 저마다 그것을 읽고 갑니다. 같은 종이를 사람 수만큼 인쇄해 돌리지 않아도 됩니다.
캐싱은 한 번 얻은 것의 복사본을 가까운 곳에 둬서 다음번에 다시 얻지 않는 일입니다. 그 복사본을 담는 저장소를 캐시라고 부릅니다. 복사본을 처음 얻어 온 곳은 원본이라고 부릅니다.
공유 캐시는 캐시 하나를 여럿이 함께 쓰는 것입니다. 그 맞은편에 하나만 쓰는 사설 캐시가 있습니다.
함께 쓰는 쪽은 계층마다 다릅니다. 웹에서는 여러 사용자가 캐시 하나를 함께 씁니다. 애플리케이션에서는 같은 프로그램을 여러 벌 띄운 애플리케이션 인스턴스들이 캐시 하나를 함께 봅니다.
프로세서 안에서도 같은 일이 있습니다. 프로세서는 CPU(Central Processing Unit, 중앙처리장치)를 말합니다. 코어는 그 안에서 명령을 따로 실행하는 단위입니다.
CPU 캐시는 대개 코어에 가까운 쪽부터 여러 단계로 나뉩니다. 그 단계 하나하나를 레벨이라고 부릅니다. 여러 코어가 캐시 레벨 하나를 함께 쓰면 그 레벨이 CPU 의 공유 캐시입니다.
세 계층에서 뜻은 같습니다. 계층마다 무엇이 달라지는지는 「갈래」가 하나씩 짚습니다.
공유 캐시라는 말에 규칙이 따로 붙은 곳은 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 캐시입니다. HTTP 캐시는 브라우저와 서버가 주고받는 응답을 담는 캐시입니다. 여럿이 쓴다는 사실 하나 때문에 공유 캐시에만 걸리는 규칙이 생깁니다.
사설 캐시와 나누는 기준
HTTP 에서 공유 캐시는 응답을 담아 두었다가 둘 이상의 사용자에게 다시 내주는 캐시입니다. 사설 캐시는 한 사용자만 씁니다. 사설 캐시는 흔히 브라우저 안에 들어 있습니다.
공유 캐시는 늘 그렇지는 않아도 대개 사용자와 서버 사이의 중간 장비에 들어 있습니다. 중간 장비로는 조직 바깥으로 나가는 길목의 프록시, 서버 앞에 선 리버스 프록시, CDN(Content Delivery Network, 콘텐츠 전송 네트워크)이 있습니다.
응답을 처음 만드는 서버는 오리진 서버라고 부릅니다. 앞에서 원본이라고 부른 것이 HTTP 에서는 오리진 서버입니다. 두 사용자가 같은 것을 차례로 요청한다고 해 봅니다. 담아 둔 응답이 아직 쓸 만한 동안에는 오리진 서버까지 가는 것이 앞사람의 요청뿐입니다.
sequenceDiagram
participant U1 as 사용자 가
participant SC as 공유 캐시
participant OS as 오리진 서버
participant U2 as 사용자 나
U1->>SC: 공지 화면을 달라
SC->>OS: 들고 있는 것이 없다 · 받아 온다
OS-->>SC: 응답
SC-->>U1: 응답 · 다음 사람 몫으로 담아 둔다
U2->>SC: 같은 공지 화면을 달라
SC-->>U2: 담아 둔 응답
Note over SC,U2: 여기서 끝난다 · 오리진 서버까지 안 간다
두 캐시는 요청 경로에서 서는 곳도 다릅니다.
flowchart TD
A["사용자 가"] --> A1["사설 캐시 · 가의 브라우저"]
B["사용자 나"] --> B1["사설 캐시 · 나의 브라우저"]
A1 --> S["공유 캐시 · 프록시나 CDN"]
B1 --> S
S --> O["오리진 서버"]
사설 캐시는 사용자마다 하나씩이라 그림에 둘이 있습니다. 공유 캐시는 둘이 함께 지나므로 하나입니다. 두 캐시가 달라지는 것을 넷으로 줄이면 다음과 같습니다.
| 사설 캐시 | 공유 캐시 | |
|---|---|---|
| 누가 쓰나 | 한 사용자 | 둘 이상의 사용자 |
| 흔히 들어 있는 곳 | 브라우저 | 프록시 · 리버스 프록시 · CDN 같은 중간 장비 |
| 담은 응답이 다른 사용자에게 가나 | 안 간다 | 간다 |
| 같은 응답을 여럿이 찾을 때 오리진 서버까지 가는 요청 | 사용자마다 첫 요청 | 담긴 응답이 쓸 만한 동안 첫 요청 하나 |
여럿이 나눠 쓰기에 못 담는 응답
공개된 이미지나 스타일 파일처럼 누가 요청해도 같은 것이 나가는 응답은 나눠 쓸수록 절약이 큽니다. 사람마다 달라야 하는 응답은 사정이 다릅니다. 장바구니 화면을 공유 캐시에 담아 두면 다음 손님이 앞사람의 장바구니를 볼 수 있습니다.
무엇을 담아도 되는지는 오리진 서버가 응답에 실어 알려 줍니다. 그 지시를 싣는 응답 헤더가
Cache-Control 입니다. 헤더는 본문과 따로 붙어 오는 이름과 값의 쌍입니다.
이 헤더의 값에 적는 낱말 하나하나를 지시어라고 합니다. Cache-Control: private 이라고 적혀
오면 그 private 이 지시어입니다. 쉼표로 여러 개를 나란히 적을 수도 있습니다.
헤더 이름 없이 private 만 붙은 응답은 공유 캐시가 담지 않습니다. 한 사용자 몫이라는 뜻입니다.
사설 캐시는 다른 저장 조건을 지키는 선에서 이 응답을 담아도 됩니다.
쿠키는 서버가 브라우저에 맡겨 두는 작은 값입니다. 서버는 Set-Cookie 응답 헤더로 쿠키를
저장하게 합니다. 브라우저는 다음 요청부터 그 쿠키를 Cookie 요청 헤더에 실어 보냅니다.
private 뒤에는 헤더 이름을 붙일 수도 있습니다. 예를 들어 Set-Cookie 를 붙이면 그 헤더만 한
사용자 몫이 됩니다. 공유 캐시는 그 헤더를 빼고 나머지 응답을 담아도 됩니다. 이 형태는 널리
구현되지 않았습니다. 캐시들은 흔히 이것을 이름 없는 private 처럼 다룹니다.
private 은 응답을 어디에 담을지만 정합니다. 응답 내용을 비밀로 지켜 주지는 못합니다.
로그인이 필요한 요청에는 규칙이 하나 더 붙습니다. 자격 증명을 실어 보내는 요청 헤더가
Authorization 입니다. 이 헤더가 붙은 요청의 응답은 공유 캐시가 담지도 않고 다음 요청에
내주지도 않는 것이 기본입니다. 이 규칙이 없으면 한 사람의 로그인 뒤 화면이 다음 사람에게 나갈
수 있습니다.
예외는 응답이 공유 캐시에 담아도 된다고 허락할 때입니다. HTTP 캐시 규칙이 이 허락으로 정해 둔
지시어는 public · s-maxage · must-revalidate 셋입니다.
public 은 원래 담으면 안 되는 응답이라도 캐시가 담아도 된다고 알리는 지시어입니다. 다른 저장
조건은 여전히 지켜야 합니다. 이미 담아도 되는 응답에는 붙일 필요가 없습니다.
s-maxage 는 공유 캐시가 이 응답을 오리진 서버에 다시 묻지 않고 쓸 시간을 적습니다.
must-revalidate 는 그 시간이 지난 응답을 오리진 서버에 다시 확인받기 전에는 내주지 말라고
정합니다. 둘은 다음 소절 「공유 캐시에만 걸리는 수명」에서 다시 봅니다.
허락을 받은 공유 캐시도 그 지시어가 거는 조건은 지켜야 합니다. s-maxage 나 must-revalidate
로 허락받은 응답은 시간이 지나면 다시 확인받기 전에 내주지 못합니다.
공유 캐시는 이 두 저장 조건을 차례로 묻습니다.
flowchart TD
A["응답에 헤더 이름 없는 private 이 붙었나"] -->|예| X["안 담는다"]
A -->|아니오| B["요청에 Authorization 이 붙었나"]
B -->|아니오| Y["나머지 저장 조건을 마저 본다"]
B -->|예| C["응답에 public · s-maxage · must-revalidate 중 하나가 있나"]
C -->|예| Y
C -->|아니오| X
두 질문을 넘은 응답도 다른 저장 조건을 마저 지켜야 담깁니다. 그 가운데 하나로, 응답에
no-store 가 없어야 합니다. no-store 는 어느 캐시에도 담지 말라는 지시어입니다. 이 조건은
사설 캐시에도 똑같이 걸립니다.
공유 캐시에만 걸리는 수명
담아 둔 응답을 오리진 서버에 다시 묻지 않고 얼마 동안 써도 되는지를 신선도라고 합니다. 그
길이가 지난 응답은 낡은 응답입니다. 길이는 응답에 실려 옵니다. max-age 지시어나 Expires
헤더가 그 길이를 적습니다.
s-maxage 는 공유 캐시에만 걸리는 길이입니다. 공유 캐시는 s-maxage 가 있으면 max-age 와
Expires 를 무시하고 이 값을 씁니다.
Cache-Control: public, max-age=60, s-maxage=600 이라고 적힌 응답이라면 브라우저의 사설 캐시는
60초, 공유 캐시는 600초를 씁니다. 사설 캐시에는 짧게, 중간의 CDN 에는 길게 들고 있게 나눌 수
있습니다.
s-maxage 는 길이만 정하지 않습니다. 이 값이 붙은 응답이 낡으면 공유 캐시는 오리진 서버에 다시
확인받기 전까지 그 응답을 내주지 못합니다. 이렇게 다시 확인받는 일을 재검증이라고 합니다.
must-revalidate 는 이 재검증 의무를 사설 캐시와 공유 캐시 모두에 겁니다. proxy-revalidate 는
같은 의무를 공유 캐시에만 겁니다.
proxy-revalidate 는 낡았을 때의 의무만 겁니다. 이것만 붙어서는 응답을 담아도 된다는 뜻이 되지
않습니다. 앞 소절의 허락 지시어 셋에도 들지 않습니다.
그래서 proxy-revalidate 는 다른 지시어와 함께 붙일 수 있습니다. 예를 들어 public 과 함께
붙이면 응답은 담아도 되는 것이 됩니다. 동시에 낡았을 때의 재검증은 공유 캐시에만 시킬 수
있습니다.
다섯 지시어가 두 캐시에 거는 것은 이렇게 다릅니다.
| 지시어 | 공유 캐시에서 | 사설 캐시에서 |
|---|---|---|
max-age |
신선한 길이. s-maxage 가 있으면 무시한다 |
신선한 길이 |
s-maxage |
신선한 길이. 낡으면 재검증 전에 못 쓴다 | 안 걸린다 |
private |
담지 않는다 | 다른 저장 조건 안에서 담아도 된다 |
public |
원래 못 담을 응답도 담아도 된다 | 원래 못 담을 응답도 담아도 된다 |
proxy-revalidate |
낡으면 재검증 전에 못 쓴다 | 안 걸린다 |
배경
사용자마다 자기 캐시만 있으면 절약은 그 사용자 안에서 끝납니다. 한 사람이 같은 것을 두 번 찾으면 두 번째가 빨라집니다. 다른 사람이 같은 것을 찾으면 그 사람의 첫 요청은 또 원본까지 갑니다. 같은 응답이 사용자 수만큼 네트워크를 지나갑니다.
캐시를 두는 까닭은 다음 요청의 응답 시간과 네트워크 사용량을 줄이는 데 있습니다. 그 절약을 사용자 사이로 넓히려고 여러 사용자가 지나는 길목에 캐시를 둡니다. 그러자 나눠 주면 안 되는 응답이 생겼습니다. 캐시가 한 사람 몫인지 여럿 몫인지를 부를 이름이 필요해졌습니다. 여럿이 쓰는 쪽을 공유 캐시, 한 사람이 쓰는 쪽을 사설 캐시라고 부릅니다.
애플리케이션에서는 다른 불편에서 출발합니다. 인스턴스마다 제 컴퓨터에 캐시를 두면 인스턴스마다 데이터 사본이 따로 생깁니다. 캐시는 과거 어느 순간의 원본을 찍어 둔 것입니다.
원본이 바뀌면 인스턴스마다 다른 판을 들고 있기 쉽습니다. 그러면 같은 질의가 인스턴스에 따라 다른 결과를 돌려줄 수 있습니다.
flowchart TD
subgraph S["인스턴스마다 둔 캐시"]
I1["인스턴스 1"] --> C1["인스턴스 1 의 캐시 · 옛 판"]
I2["인스턴스 2"] --> C2["인스턴스 2 의 캐시 · 새 판"]
end
C1 --> O["바뀐 원본"]
C2 --> O
캐시를 한 곳에 두면 모든 인스턴스가 같은 캐시 데이터를 봅니다.
예시
세 예시는 계층이 다릅니다. HTTP 캐시 서버 · 웹 프레임워크 · 운영체제 순입니다.
Varnish 의 기본 설정
Varnish 는 백엔드 서버 앞에서 응답을 담아 두는 HTTP 캐시 서버입니다. 여러 사용자의 요청을
받으므로 공유 캐시입니다. 따로 설정하지 않으면 기본 설정 파일 builtin.vcl 이 돕니다. 그 안에
요청을 거르는 대목이 있습니다.
sub vcl_req_authorization {
if (req.http.Authorization) {
# Not cacheable by default.
return (pass);
}
}
sub vcl_req_cookie {
if (req.http.Cookie) {
# Risky to cache by default.
return (pass);
}
}
요청에 Authorization 이나 Cookie 헤더가 있으면 return (pass) 로 캐시를 건너뛰고 백엔드로
곧장 갑니다. 「상세」의 규칙은 Authorization 이 붙은 요청의 응답을 허락 없이 쓰지 못하게 할
뿐입니다. 이 기본 설정은 한 걸음 더 나가 쿠키가 붙은 요청까지 캐시를 건너뜁니다.
응답 쪽에도 같은 성격의 대목이 있습니다.
sub vcl_beresp_cookie {
if (beresp.http.Set-Cookie) {
call vcl_beresp_hitmiss;
}
}
sub vcl_beresp_control {
if (beresp.http.Surrogate-control ~ "(?i)no-store" ||
(!beresp.http.Surrogate-Control &&
beresp.http.Cache-Control ~ "(?i:no-cache|no-store|private)")) {
call vcl_beresp_hitmiss;
}
}
beresp 는 백엔드가 돌려준 응답입니다. 이 응답에 Set-Cookie 헤더가 있으면 vcl_beresp_hitmiss
로 보냅니다. vcl_beresp_hitmiss 는 응답을 다음 요청에 내줄 복사본으로 남기지 않는 처리입니다.
그래서 기본 설정에서 Set-Cookie 가 붙은 응답은 캐시에 담기지 않습니다.
Cache-Control 에 no-cache · no-store · private 중 하나가 있는 응답도 같은 처리로 갑니다.
no-cache 는 담아 두더라도 쓸 때마다 오리진 서버에 다시 확인받으라는 지시어입니다.
Surrogate-Control 은 백엔드가 응답에 붙여 보내는 또 하나의 캐시 지시 헤더입니다. 이 헤더가
있으면 기본 설정은 Cache-Control 대신 이 헤더에 no-store 가 있는지만 봅니다.
Django 의 캐시 설정
Django 는 파이썬 웹 프레임워크입니다. 캐시를 어디에 둘지는 설정의 CACHES 로 고릅니다.
로컬 메모리 캐시를 고르면 프로세스마다 자기 사설 캐시 인스턴스를 따로 갖습니다. 프로세스 사이에 캐시를 나눠 쓸 수 없습니다. 메모리도 그만큼 아껴 쓰지 못합니다. 운영 환경에는 아마 맞지 않습니다. 개발할 때 쓰기에 알맞습니다.
Memcached 를 고르면 캐시가 프로세스 안이 아니라 따로 띄운 Memcached 데몬에 있습니다. 데몬은 뒤에서 늘 떠 있는 서버 프로그램입니다. 같은 설정을 읽은 프로세스들은 같은 데몬을 캐시로 봅니다.
Memcached 는 여러 서버에 띄운 데몬을 묶어 캐시 하나처럼 쓸 수 있습니다. 그러려면 LOCATION 에
서버 주소를 모두 적습니다. 그러면 값을 서버마다 겹쳐 담을 필요가 없습니다.
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": [
"172.19.26.240:11211",
"172.19.26.242:11211",
],
}
}
LOCATION 에 두 서버의 주소와 포트 11211 을 적었습니다. 캐시는 이 두 Memcached 인스턴스에 걸쳐
함께 쓰입니다. 이 설정을 읽은 프로그램은 두 서버를 캐시 하나로 다룹니다. LOCATION 은 리스트
대신 세미콜론이나 쉼표로 이은 문자열로 적어도 됩니다.
리눅스 sysfs 의 캐시 공유 목록
리눅스는 CPU 캐시의 생김새를 sysfs 로 보여 줍니다. sysfs 는 커널이 내부 정보를 파일처럼 읽게 내놓는 파일 시스템입니다. CPU 마다, 그리고 캐시마다 디렉터리가 하나씩 있습니다.
/sys/devices/system/cpu/cpu*/cache/index*/
공유 여부는 논리 CPU 목록으로 적힙니다. 논리 CPU 는 운영체제가 CPU 하나로 세는 실행 단위입니다. 이 디렉터리에 든 속성 파일 가운데 다섯은 아래와 같습니다.
| 속성 | 담는 것 |
|---|---|
level |
여러 레벨로 된 캐시에서 이 캐시가 몇 번째 레벨인지 |
type |
명령어만 담나(Instruction) · 데이터만 담나(Data) · 둘 다 담나(Unified) |
size |
캐시 전체 크기. 킬로바이트 단위 |
shared_cpu_list |
이 캐시를 함께 쓰는 논리 CPU 목록 |
shared_cpu_map |
같은 목록을 비트 마스크로 적은 것 |
shared_cpu_list 에 CPU 가 하나만 있으면 그 캐시는 그 CPU 혼자 씁니다. 둘 이상이면 그 캐시가
그 CPU 들의 공유 캐시입니다.
갈래
갈래를 나누는 축은 누가 캐시를 함께 쓰나입니다. 함께 쓰는 쪽이 사용자면 HTTP 공유 캐시입니다. 애플리케이션 인스턴스면 애플리케이션 공유 캐시입니다. 코어면 CPU 공유 캐시입니다. 셋은 하나를 여럿이 쓰는 모양이 같습니다. 노리는 것과 함께 써서 생기는 일이 다릅니다.
flowchart TD
subgraph H["HTTP 공유 캐시"]
H1["사용자 가"] --> HC["공유 캐시"]
H2["사용자 나"] --> HC
HC --> HO["오리진 서버"]
end
subgraph A["애플리케이션 공유 캐시"]
A1["인스턴스 1"] --> AC["캐시 서비스"]
A2["인스턴스 2"] --> AC
AC --> AO["원본 데이터"]
end
subgraph C["CPU 공유 캐시"]
C1["코어 0"] --> P1["코어 0 전용 레벨"]
C2["코어 1"] --> P2["코어 1 전용 레벨"]
P1 --> CC["함께 쓰는 바깥쪽 레벨"]
P2 --> CC
CC --> CM["메모리"]
end
HO ~~~ A1
AO ~~~ C1
HTTP 공유 캐시
대개 사용자와 서버 사이에 서서 여러 사용자가 함께 쓸 응답을 담습니다. 누가 두었나에 따라 프록시 캐시와 매니지드 캐시로 나뉩니다. 둘은 요청 경로에서 서는 곳도 다릅니다.
flowchart TD
U["사용자"] --> B["사설 캐시 · 브라우저"]
B --> P["프록시 캐시 · 조직 바깥으로 나가는 길목"]
P --> M["매니지드 캐시 · 리버스 프록시나 CDN"]
M --> O["오리진 서버"]
프록시 캐시는 일부 프록시가 접근 통제와 함께 맡는 캐시입니다. 조직 바깥으로 나가는 통신량을 줄이려고 둡니다. 대개 서비스 개발자가 관리하지 않으므로 개발자는 알맞은 HTTP 헤더 같은 수단으로 다뤄야 합니다. 최근에는 HTTPS(HyperText Transfer Protocol Secure, 암호화한 HTTP)가 널리 쓰입니다. 그래서 경로 위의 프록시 캐시는 많은 경우 응답을 열어 보지 못한 채 넘기기만 합니다.
매니지드 캐시는 오리진 서버의 부하를 덜려고 서비스 개발자가 직접 둔 캐시입니다. 콘텐츠를 효율
있게 내보내는 것도 목적입니다. 리버스 프록시와 CDN 이 매니지드 캐시에 듭니다. 동작은 제품마다
다릅니다. 대개 Cache-Control 헤더와 그 제품의 설정 파일이나 대시보드로 다룹니다.
애플리케이션 공유 캐시
여러 프로세스와 여러 머신이 함께 접근하는 캐시입니다. 캐시는 애플리케이션 인스턴스 바깥에 둡니다. 대개 별도 서비스로 띄웁니다. 노리는 것은 모든 인스턴스가 같은 캐시 데이터를 보는 것입니다. HTTP 공유 캐시가 오리진 서버까지 가는 요청을 줄이려는 것과 출발점이 다릅니다.
많은 캐시 서비스가 서버 여러 대를 묶은 클러스터로 돕니다. 클러스터는 서버 여러 대를 하나처럼 굴리는 묶음입니다. 데이터는 캐시 서비스의 소프트웨어가 클러스터 안에 알아서 나눠 담습니다.
인스턴스는 캐시 서비스에 요청만 보냅니다. 데이터가 어느 서버에 있는지는 캐시 서비스 쪽이 찾습니다. 서버를 더하면 캐시를 키울 수 있습니다.
CPU 공유 캐시
CPU 캐시는 대개 여러 레벨로 되어 있습니다. 코어에 가까운 레벨은 코어마다 따로 둡니다. 바깥쪽 레벨은 여러 코어가 함께 쓰는 구성이 흔합니다. 함께 쓰는 레벨에서는 코어들이 같은 용량을 나눠 씁니다.
운영체제는 캐시마다 그것을 함께 쓰는 CPU 목록을 들고 있습니다. 「예시」의 shared_cpu_list 로
이 목록을 보여 줍니다.
대가
함께 쓰면 절약이 커집니다. 그 대신 캐시에 잘못 담긴 것이 함께 쓰는 모두에게 갈 수 있습니다. 애플리케이션에서는 캐시가 쓰는 쪽에서 멀어집니다. 캐시 서비스라는 부품도 하나 늡니다.
다른 사용자에게 가는 개인 응답
사설 캐시가 아닌 캐시에 사람마다 다른 응답이 담기면 다른 사용자가 그것을 꺼내 갈 수 있습니다. 의도하지 않은 정보 유출로 이어질 수 있습니다.
자격 증명처럼 비공개라고 여긴 민감 정보가 구현이나 배포의 결함 때문에 캐시에 담길 수 있습니다. 그러면 권한 없는 사람에게 드러납니다. 이런 결함은 흔히 캐시 동작을 잘못 이해한 데서 옵니다.
Set-Cookie 헤더는 캐시를 막지 않습니다. 담아도 되는 응답에 Set-Cookie 가 붙어 있어도 그
응답은 다음 요청에 쓰일 수 있습니다. 그렇게 다음 요청에 쓰이는 일도 흔합니다.
서버가 이런 응답의 캐시를 다루고 싶으면 알맞은 Cache-Control 을 붙이기를 권합니다. 「예시」의
Varnish 기본 설정은 이런 응답을 담지 않는 쪽을 골랐습니다.
여러 사용자에게 퍼지는 오염된 응답
캐시에 악의적인 내용을 담으면 공격자의 손이 여러 사용자에게 닿을 수 있습니다. 이것을 캐시 포이즈닝이라고 합니다. 공격자는 구현 결함이나 높은 권한 같은 수단으로 응답을 캐시에 끼워 넣습니다. 공유 캐시가 그 내용을 많은 클라이언트에게 나눠 줄 때 특히 효과가 큽니다.
로컬 메모리보다 먼 캐시 서비스
애플리케이션 공유 캐시는 인스턴스마다 곁에 두지 않으므로 읽기가 더 오래 걸립니다. 별도 캐시 서비스를 두는 만큼 시스템이 더 복잡해질 수 있습니다.
캐시 서비스는 애플리케이션 바깥에 따로 섭니다. 그래서 캐시 서비스가 멈추는 경우를 새로 따져야 합니다. 애플리케이션이 캐시 서비스 없이는 못 도는 구조로 짜이면, 캐시 서비스가 돌아오기를 기다리다 응답을 멈추거나 실패할 수 있습니다.
이런 결정적(critical) 의존을 만들지 않으려면 공유 캐시가 멈춰도 계속 도는 길을 따로 짜 두어야 합니다. 그만큼 설계할 것이 늡니다.
관련 항목
공유 캐시가 서는 중간 장비
프록시 · 리버스 프록시 · CDN · 로드 밸런서 · API 게이트웨이
HTTP 공유 캐시를 사이에 둔 양 끝
클라이언트 · 사용자 에이전트 · 오리진 서버 · 백엔드 서버
공유 캐시와 맞세워지는 반대편 캐시
사설 캐시 · 브라우저 캐시 · 로컬 캐시
저장 매체로 나눈 캐시 종류
인메모리 캐시 · 디스크 캐시 · 페이지 캐시
공유 캐시가 속하는 상위 분류
공유 캐시의 하위 종류
프록시 캐시 · 매니지드 캐시 · 리버스 프록시 캐시 · 분산 캐시
공유 캐시의 저장 여부와 수명을 정하는 헤더·지시어
Cache-Control · s-maxage · max-age · Expires · Age · no-store · no-cache · private · public · proxy-revalidate · must-revalidate · Authorization · Set-Cookie · Surrogate-Control
공유 캐시가 응답을 읽고 넘기는 HTTP 통신 요소
HTTPS · HTTP 헤더 · 요청 헤더 · 응답 헤더 · 쿠키
공유 캐시가 요청과 응답을 맞춰 보는 기준
캐시 키 · Vary · URL · HTTP 메서드 · 이중 키
공유 캐시가 담은 응답을 언제까지 쓸지 정하는 개념
신선도 · 재검증 · 조건부 요청 · ETag · Last-Modified · 낡은 응답
공유 캐시에 담긴 응답을 지우거나 밀어내는 수단
무효화 · 퍼지 · 축출 · TTL · hit-for-miss
공유 캐시에서 터지는 문제
캐시 스탬피드 · 캐시 미스 · 캐시 포이즈닝 · 캐시 오염 · 타이밍 공격
공유 캐시가 줄이는 사본 어긋남
공유 캐시를 함께 쓰는 실행 주체
애플리케이션 인스턴스 · 프로세스 · 코어 · 논리 CPU
CPU 공유 캐시가 속하는 프로세서 캐시 구조
CPU 캐시 · 캐시 레벨 · 캐시 계층 · 마지막 단계 캐시
공유 캐시를 설정하거나 들여다보는 인터페이스
sysfs · VCL · Django 캐시 프레임워크
공유 캐시 노릇을 하는 제품
Varnish · Redis · memcached · Squid
애플리케이션 공유 캐시를 짓는 데 쓰는 기법
cache-aside · 서킷 브레이커 · 클러스터 · 일관성 해싱
공유 캐시를 정의하는 표준·문서
다른 이름: shared cache · 공용 캐시