5장. Caching 무효화
이 장에서는 Caching된 콘텐츠를 무효화하는 방법에 대해 설명한다. 업계용어로 Purge로 통칭하지만 다양한 상황과 환경으로 인해 세분화된 API가 필요하다.
원본으로부터 캐싱된 콘텐츠는 TTL (Time To Live) 에 기반한 갱신주기를 가진다. 하지만 명백히 콘텐츠가 변경되었고 관리자가 이를 즉시 반영하고 싶을 경우 TTL (Time To Live) 이 만료될 때까지 기다릴 필요는 없다. Purge / Expire / HardPurge 등을 사용하면 즉시 콘텐츠를 무효화시킬 수 있다.
무효화 API는 단순히 브라우저에 의해 호출되는 경우도 있지만 자동화되어 있는 경우가 많다. 가령 FTP를 통한 파일 업로드가 끝나면 즉시 Purge 를 호출하는 식이다. 관리자는 다음과 같이 몇가지 동작방식에 대해 설정할 수 있다.
# server.xml - <Server><VHostDefault><Options>
# vhosts.xml - <Vhosts><Vhost><Options>
<Purge2Expire>NONE</Purge2Expire>
<RootPurgeExpire>ON</RootPurgeExpire>
<RootHardPurge>ON</RootHardPurge>
<ResCodeNoCtrlTarget>200</ResCodeNoCtrlTarget>
<ResCodeDenyCtrlTarget>200</ResCodeDenyCtrlTarget>
<Purge2Expire> (기본: NONE)
Purge 요청을 설정에 따라 Expire 로 처리한다. 예를 들어 특정 패턴(*.jpg)를 Purge 하는 경우 의도하지 않게 많은 컨텐츠가 삭제되어 원본에 과도한 부하를 발생시킬 수 있다. 이런 경우 Expire 로 처리하도록 설정하면 과도한 원본부하를 방지할 수 있다.
<RootPurgeExpire> (기본: ON)
전체 콘텐츠에 대한 의도하지 않은 Purge / Expire 는 과도한 원본서버 부하를 발생시킬 수 있다. 이 설정을 통하여 전체 콘텐츠에 대한 Purge / Expire 를 차단할 수 있다. 이 설정은
<Purge2Expire>
보다 우선한다.<RootHardPurge> (기본: ON)
전체 콘텐츠(
/*
) 에 대한 HardPurge 는 모든 캐싱을 삭제하기 때문에 매우 위험하다.<ResCodeNoCtrlTarget> (기본: 200)
Purge , Expire , HardPurge , ExpireAfter 의 대상객체가 없을 때의 HTTP 응답코드를 설정한다.
<ResCodeDenyCtrlTarget> (기본: 200)
<RootPurgeExpire>
,<RootHardPurge>
설정에 의해서 Control API 호출이 거부 될 경우 설정된 응답코드로 응답 한다.
대상 지정은 URL, 패턴 2가지로 표현한다.
example.com/logo.jpg // URL
example.com/img/ // URL
example.com/img/*.jpg // 패턴
example.com/img/* // 패턴
명확한 URL 외에 패턴(*.jpg)으로 무효화가 가능하다. 하지만 작업을 수행하기 전까지 대상개수를 명확히 알 수 없다. 이는 자칫 관리자의 의도와 다르게 너무 많은 대상을 지정할 수 있다. 이는 실제로 CPU자원을 너무 많이 소모하게 되어 시스템 전체에 부담을 줄 수 있다.
그러므로 실 서비스 중에는 명확한 URL만을 사용할 것을 강력히 권장한다. 패턴표현은 서비스에서 배제된 상태에서 관리용도로 사용하기 위함이다.
참고
보안적인 이유로 example.com/files/ 같은 특정 디렉토리에 대한 접근은 403 FORBIDDEN등으로 차단된다. 하지만 루트 디렉토리는 예외를 가진다. 예를 들어 사용자가 example.com에 접근하면 브라우저는 루트 디렉토리(/)를 요청한다.
GET / HTTP/1.1
Host: example.com
이에 대해 웹서버는 관리자가 설정한 기본 페이지(아마도 index.html 또는 index.htm)로 응답한다. 분명 웹 서비스 구성에서 루트 디렉토리(/)는 디렉토리가 아닌 페이지로 동작한다.
하지만 Cache서버는 루트 디렉토리(/)에 접근했더니 200 OK 페이지가 왔다고 이해한다. 심지어 원본서버가 어떤 페이지를 응답했는지 알지 못한다. 간단히 정리하면 Cache서버의 관점에서는 디렉토리 표현도 URL의 한 종류일 뿐이다.
example.com/img/ // example.com 가상호스트의 /img/ 에 접근한 결과 페이지
example.com/ // example.com 가상호스트의 기본 페이지(/)
example.com/img/* // example.com 가상호스트의 /img 디렉토리와 그 하위 페이지
example.com/* // example.com 가상호스트의 모든 콘텐츠
Purge
타겟 컨텐츠를 무효화시켜 원본서버로부터 컨텐츠를 다시 다운로드 받도록 한다. Purge후 최초 접근 시점에 원본서버로부터 컨텐츠를 다시 캐싱한다. 만약 원본서버에 장애가 발생하여 컨텐츠를 가져올 수 없다면 무효화된 컨텐츠를 다시 복원시켜 서비스에 장애가 없도록 처리한다. 이렇게 복원된 컨텐츠는 해당 시점으로부터 ConnectTimeout설정만큼 뒤에 갱신한다.
http://127.0.0.1:10040/command/purge?url=...
타겟 컨텐츠는 URL, 패턴으로 지정할 수 있을 뿐만 아니라 “|”(Vertical Bar)를 구분자를 사용하여 복수의 도메인에 복수의 타겟을 지정할 수 있다. 만약 도메인 이름이 생략되었다면 최근 사용된 도메인을 사용한다.
http://127.0.0.1:10040/command/purge?url=http://www.site1.com/image.jpg
http://127.0.0.1:10040/command/purge?url=www.site1.com/image.jpg
http://127.0.0.1:10040/command/purge?url=www.site1.com/image/bmp/
http://127.0.0.1:10040/command/purge?url=www.site1.com/image/*.bmp
http://127.0.0.1:10040/command/purge?url=www.site1.com/image1.jpg|/css/style.css|/script.js
http://127.0.0.1:10040/command/purge?url=www.site1.com/image1.jpg|www.site2.com/page/*.html
결과는 JSON형식으로 제공된다. 타겟 컨텐츠 개수/용량 및 처리시간(단위: ms)이 명시된다. 이미 Purge 된 컨텐츠는 다시 Purge되지 않는다.
{
"version": "2.0.0",
"method": "purge",
"status": "OK",
"result": { "Count": 24, "Size": 3747491, "Time": 12 }
}
<Purge2Expire>
를 통해 특정조건의 Purge를 Expire로 동작하도록 설정할 수 있다.
결과없는 응답에 대해서는 <ResCodeNoCtrlTarget>
로 HTTP 응답코드를 설정할 수 있다.
참고
원본서버가 장애로 인해 모두 배제되었다면 컨텐츠를 갱신할 수 없기 때문에 Purge가 동작하지 않는다.
Expire
타겟 컨텐츠의 TTL을 즉시 만료시킨다. Expire후 최초 접근 시점에 원본서버로부터 변경여부를 확인한다. 변경되지 않았다면 TTL연장만 있을 뿐 컨텐츠 다운로드는 발생하지 않는다.
http://127.0.0.1:10040/command/expire?url=...
그 외의 모든 동작은 Purge 와 동일하다.
ExpireAfter
타겟 컨텐츠의 TTL만료 시간을 현재(API호출시점)로부터 입력된 시간(초)만큼 뒤에 설정한다. ExpireAfter로 만료시간을 앞당겨 컨텐츠를 더 빨리 갱신하거나, 반대로 만료시간을 늘려 원본서버 부하를 줄일 수 있다.
http://127.0.0.1:10040/command/expireafter?sec=86400&url=...
함수 호출규격은 Purge / Expire 와 유사하지만 sec파라미터(단위: 초)를 통해
TTL만료 시간을 지정할 수 있다.
sec가 생략된다면 기본 값은 1일(86400초)로 설정되며 0을 입력할 경우 실패한다.
결과는 Purge / Expire 와 동일하지만 원본서버 장애여부와 상관없이 동작한다.
결과없는 응답에 대해서는 <ResCodeNoCtrlTarget>
로 HTTP 응답코드를 설정할 수 있다.
참고
ExpireAfter는 캐싱되어있는 컨텐츠의 현재 만료시간만을 설정할 뿐 커스텀TTL이나 설정된 기본 TTL을 변경시키는 API가 아니다. ExpireAfter 호출뒤에 캐싱된 컨텐츠들은 영향을 받지 않는다.
url파라미터를 먼저 입력하는 경우 sec파라미터가 url파라미터의 QueryString으로 인식될 수 있다. 그러므로 sec파라미터가 먼저 입력되는 것이 안전하다.
HardPurge
Purge / Expire / ExpireAfter 이상의 API는 원본서버 장애상황에서도 컨텐츠가
사라지지 않고 정상적으로 동작한다.
하지만 HardPurge는 컨텐츠의 완전한 삭제를 의미한다.
HardPurge는 가장 강력한 삭제방법이지만 삭제한 컨텐츠는 원본서버에 장애가 발생해도 되살릴 수 없다.
결과없는 응답에 대해서는 <ResCodeNoCtrlTarget>
로 HTTP 응답코드를 설정할 수 있다.
http://127.0.0.1:10040/command/hardpurge?url=...
Purge 기본동작
Purge API가 호출될 때 컨텐츠 복구 여부를 선택한다.
# server.xml - <Server><Cache>
<Purge>Normal</Purge>
HTTP Method
무효화 API를 확장 HTTP Method로 호출할 수 있다.
PURGE /sample.dat HTTP/1.1
host: ston.winesoft.co.kr
HTTP Method는 기본적으로 Manager포트와 서비스(80)포트에서 동작한다. 서비스포트로 요청되는 HTTP Method의 관리자 설정 에서 설정한다.
비동기 모드를 사용하는 경우 다음과 같이 HTTP Method가 변경된다.
// 비동기 expire
ASYNCEXPIRE /index.html HTTP/1.1
Host: foo.com:10040
// 비동기 purge
ASYNCPURGE /* HTTP/1.1
Host: foo.com:10040
// 비동기 hardpurge
ASYNCHARDPURGE /*.html HTTP/1.1
Host: foo.com:10040
POST 규격
무효화 API를 다음과 같이 POST로 호출할 수 있다.
POST /command/purge HTTP/1.1
Content-Length: 37
url=http://ston.winesoft.co.kr/sample.dat
동기/비동기 무효화
무효화 API의 기본동작은 동기방식이다. 설정을 통해 비동기로 동작하도록 설정할 수 있다.
#server.xml
<Cache>
<ControlAPI>sync</ControlAPI>
<AsyncControlTarget>PATTERN</AsyncControlTarget>
</Cache>
<ControlAPI>
sync (기본)
무효화 API가 동기로 동작한다.async
무효화 API가 비동기로 동작한다.
<AsyncControlTarget>
비동기 무효화로 구성된 상태라도, 요청된 URL에 따라 선별적으로 비동기 처리한다.pattern (기본)
패턴(*) 요청에 대해서만 비동기 처리한다.all
모든 요청을 비동기 처리한다.
비동기로 동작하는 경우 무효화 요청은 큐에 저장되며 백그라운드로 수행된다.
참고
백그라운드 수행 이전이라도 접근되는 콘텐츠가 무효화 대상이라면 즉시 만료된다.
비동기 API를 호출했으나 동기로 처리되었다면
201 Created
로 응답한다.
호출 규격은 아래과 같다.
/command/async/expire?url=foo.com/index.html
/command/async/purge?url=foo.com/*
/command/async/hardpurge?url=foo.com/*.jpg
비동기 무효화 동작의 세부 설정은 다음과 같다.
# server.xml - <Server><Cache>
<Performance>
<MaxAsyncCacheCtrl>100000</MaxAsyncCacheCtrl>
<PreCacheControl Max="5000" FirstOnly="OFF">ON</PreCacheControl>
</Performance>
<MaxAsyncCacheCtrl> (기본: 100000)
비동기 무효화 최대 저장개수<PreCacheControl> (기본: ON)
접근되는 콘텐츠에 대해 저장된 비동기 무효화를 매칭한다.Max (기본: 5000)
가상호스트별로 매칭할 비동기 무효화 최대 개수FirstOnly (기본: OFF)
ON인 경우 첫번째 미칭에 대해서 반영하며, OFF인 경우 전체 무효화를 검사해 가장 강한 표현을 반영한다.
비동기 무효화 관리 API
비동기 무효화가 활성화되어 있다면 등록된 무효화 요청을 아래와 같이 조회할 수 있다.
# 전체 가상호스트의 비동기 무효화 요약정보
http://127.0.0.1:10040/monitoring/asynctrl/actives
# 특정 가상호스트들의 비동기 무효화 요약정보
http://127.0.0.1:10040/monitoring/asynctrl/actives?vhosts=foo.com,bar.com
# 전체 가상호스트의 비동기 무효화 상세정보
http://127.0.0.1:10040/monitoring/asynctrl/actives?detail=true
# 특정 가상호스트의 비동기 무효화 상세정보
http://127.0.0.1:10040/monitoring/asynctrl/actives?vhosts=foo.com,bar.com&detail=true
vhosts
쿼리스트링이 없다면 전체 가상호스트를 조회한다. 콤마로 멀티 가상호스트 입력이 가능하며 해당 가상호스트만 조회한다.detail
쿼리스트링이true
라면 가상호스트별로 저장된 비동기 무효화 목록 상세정보를 출력한다.
상세정보 응답은 vhosts[].prectrl.list
를 제공한다.
{
"queue": {
"used": 3,
"max": 100000
},
"prectrl": {
"firstonly": true,
"max": 1024
},
"vhosts": [
{
"name": "foo.com",
"prectrl": {
"enable": true,
"used": 3,
"max": 1024,
"list": [
{
"command": "purge",
"timestamp": "2023-01-13T08:58:34Z",
"url": "/*.jpg"
},
{
"command": "purge",
"timestamp": "2023-01-13T08:58:35Z",
"url": "/*.bmp"
},
{
"command": "purge",
"timestamp": "2023-01-13T08:58:36Z",
"url": "/*"
}
]
}
},
{
"name": "bar.com",
"prectrl": {
"enable": true,
"used": 0,
"max": 1024,
"list": [
]
}
}
]
}
관리 API는 다음과 같다.
# 모든 비동기 무효화 정보를 초기화한다.
http://127.0.0.1:10040/command/async/asynctrl/reset
# 특정 가상호스트의 prectrl만 초기화한다.
# 단, 비동기 무효화 항목은 삭제되지 않고 수행된다.
http://127.0.0.1:10040/command/async/asynctrl/prectrl/reset?vhost=foo.com