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 로 처리하도록 설정하면 과도한 원본부하를 방지할 수 있다.

    • NONE Expire 로 처리하지 않는다.

    • ROOT 도메인 전체(/*)에 대한 PurgeExpire 로 처리한다.

    • PATTERN 모든 패턴 PurgeExpire 로 처리한다.

    • ALL 모든 PurgeExpire 로 처리한다.

  • <RootPurgeExpire> (기본: ON)

    전체 콘텐츠에 대한 의도하지 않은 Purge / Expire 는 과도한 원본서버 부하를 발생시킬 수 있다. 이 설정을 통하여 전체 콘텐츠에 대한 Purge / Expire 를 차단할 수 있다. 이 설정은 <Purge2Expire> 보다 우선한다.

  • <RootHardPurge> (기본: ON)

    전체 콘텐츠( /* ) 에 대한 HardPurge 는 모든 캐싱을 삭제하기 때문에 매우 위험하다.

    • ON 전체 콘텐츠의 HardPurge 를 허용한다.

    • OFF 전체 콘텐츠의 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>
  • <Purge>

    • Normal (기본) Purge 로 동작한다. (원본장애 시 복구 함)

    • Hard HardPurge 로 동작한다. (원본장애 시 복구하지 않음)

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