체인함수 개발가이드

함수체인은 아래와 같이 목적이 다른 함수들을 연결하여 콘텐츠를 생산/가공하는 방식을 말한다.

../_images/cf1.png

함수체인을 구성하는 개별 함수를 체인함수 라고 부른다. 실시간 이미지 가공 패턴은 HTTP 처리함수 , 이미지 처리함수 , 원본 캐싱함수 를 연결하여 구현된 함수체인으로 이해할 수 있다.

체인함수 디스패치 맵

RT 외부의 체인함수는 RTvhosts.xml<DispatchMap> 을 통해 연결된다.

# vhosts.xml - <Vhosts>

<Vhost Name="foo.com">
  <DispatchMap>
    <Function Name="unzip" Keyword="unzip" Location="remote" />
    <Function Name="epubedit" Keyword="epubedit" Conflict="skip" />
    <Function Name="xcdr" Keyword="videopt" Partial="off" Location="remote1" />
  </DispatchMap>
</Vhost>
Function

체인함수

Name

체인함수의 고유이름. setting.jsonfunctions 하위의 설정노드와 같아야 한다.

Keyword

URL상에 명시될 함수호출 이름. 아래 규범을 권장한다.

/{원본 URL}/{Keyword}/{command1}/{param1}/{command2}/{param2}
Location (기본: remote)

함수 위치

  • local RT 내장함수로 라우팅한다.

  • remote0 Core 기본포트로 라우팅한다.

  • remote1 Core 기본포트 + 1로 라우팅한다.

  • remote2 Core 기본포트 + 2로 라우팅한다. reserved

Note

remote 계열 설정은 workload를 분배하는 정책에 따라 함수를 등록하는 주체 core 가 결정한다.

Conflict (기본: skip)

동일한 Name 의 함수가 맵핑되었을 때의 충돌정책

  • skip (기본) 이전함수를 유지하고 신규함수를 폐기한다.

  • overwrite 이전함수를 신규함수로 덮어씌운다.

Partial (기본: off)

on 이라면 체인함수 Range 처리 를 허용한다.

Refresh (기본: ims)

체인함수와 캐시 갱신 정책

체인함수가 정상적으로 등록되었다면 info.log 에 함수맵이 기록된다.

[DispatchMap] Map(3): [/dims/, dims, local],[/unzip/, unzip, remote],[/epubedit/, epubedit, remote]

체인함수 확장헤더

다음은 클라이언트가 dims 함수를 이용해 가로 100으로 리사이즈하는 요청이다.

GET /sample.jpg/resize/100
Host: foo.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7

체인함수인 dims 로 호출되는 요청은 다음과 같다.

GET /sample.jpg HTTP/1.1
Host: foo.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
X-M2X-Forwarded-For: 128.134.57.105
X-M2X-Forwarded-LocalAddr: 10.10.10.10:80
X-M2X-Forwarded-Proto: http
X-M2X-Forwarded-Context-Id: 15d50ea4-6d0a-408d-acbc-c31e4484956c
X-M2X-Function-Name: dims
X-M2x-Function-ClientUrl: /sample.jpg/dims/resize/100
X-M2X-Function-Session: nolog;nostats;nourlrewrite;nosessionurlrewrite;recursive;reqfilemeta;keepalive=600;

X-M2X- 로 시작되는 다양한 확장함수 호출규격을 준수해야 올바른 구현이 가능하다.

헤더 포워딩 정책

체인함수는 함수체인안에서 동작하기에 다음 함수 호출에 대한 규칙을 준수해야 해야 instant bypass 같은 상태에서도 안전한 동작이 보장된다.

Note

반드시 아래 헤더 포워딩 정책을 준수해야 한다.

  • X-M2X- 로 시작하지 않는 모든 헤더

  • X-M2X-Forwarded- 로 시작하는 헤더

  • X-M2X-Function-Session 헤더

  • X-M2X-Var- 로 시작하는 헤더 중 현재 함수에서 소비하지 않은 헤더

위 호출 예제의 의미를 나누어 보면 아래와 같다.

GET /sample.jpg/transcoder/captrue/ts=10 HTTP/1.1

# [포워딩] 클라이언트 입력헤더. X-M2X- 로 시작하지 않는 모든 헤더를 포워딩한다.
Host: foo.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1

# [포워딩] X-M2X-Forwarded- 계열
X-M2X-Forwarded-For: 128.134.57.105
X-M2X-Forwarded-LocalAddr: 10.10.10.10:80
X-M2X-Forwarded-Proto: http
X-M2X-Forwarded-Context-Id: 15d50ea4-6d0a-408d-acbc-c31e4484956c

# [삭제]
X-M2X-Function-Name: dims
X-M2x-Function-ClientUrl: /sample.jpg/dims/resize/100

# [포워딩]
X-M2X-Function-Session: nolog;nostats;nourlrewrite;nosessionurlrewrite;recursive;reqfilemeta;keepalive=600;

X-M2X-Function- 확장헤더

X-M2X-Function- 계열 확장헤더는 함수 디스패치를 위해 존재한다.

헤더

설명

X-M2X-Function-Name

요청 호출함수

X-M2x-Function-ClientUrl

요청 클라이언트가 호출한 URL

X-M2X-Function-Session

요청 함수체인 세션플래그

X-M2X-Function-Info

응답 함수 정보메시지. origin.logx-sc-chain-info 필드에 기록된다.

X-M2X-Function-Error

응답 함수 에러메시지. origin.logx-sc-chain-error 필드에 기록된다.

체인함수 브로커는 위 파라미터를 파싱하여 체인함수를 연결한다. 함수가 디스패치되었다면 다음 함수체인을 위해 다음과 같이 X-M2X-Function- 계열 확장헤더는 삭제되어야 한다.

GET /sample.jpg HTTP/1.1
Host: foo.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
X-M2X-Forwarded-For: 128.134.57.105
X-M2X-Forwarded-LocalAddr: 10.10.10.10:80
X-M2X-Forwarded-Proto: http
X-M2X-Forwarded-Context-Id: 15d50ea4-6d0a-408d-acbc-c31e4484956c

X-M2X-Forwarded- 확장헤더

X-M2X-Forwarded- 계열 확장헤더는 클라이언트의 신원을 전달하기 위해 존재한다.

헤더

설명

X-M2X-Forwarded-For

클라이언트 IP

X-M2X-Forwarded-Proto

클라이언트 프로토콜 http , https-{버전}

X-M2X-Forwarded-LocalAddr

서버 IP:Port

X-M2X-Forwarded-HookMsg

원본 요청 재정의

X-M2X-Forwarded-Context-Id

클라이언트 요청 ID

Important

만약 체인함수가 RT 를 통하지 않고 외부통신을 진행한다면 반드시 X-M2X- 로 시작하는 모든 확장헤더를 삭제해야 한다.

X-M2X-Var- 확장헤더

X-M2X-Var- 계열 확장헤더는 특정 모듈로 파라미터를 전달하기 위해 존재한다.

헤더

파라미터

설명

X-M2X-Var-Cache-Ttl

elapsed=1.5;value=600;

콘텐츠 다운로드 트랜잭션이 elapsed (초) 보다 오래 소요되면 트랜잭션 완료시점으로부터 value (초) 만큼 TTL을 부여한다.

Note

조정 조건은 다음 조건을 모두 만족해야 한다.

  • 200 OK

  • 입력파라미터가 모두 유효해야 함

  • 함수체인이 아닌 원본 객체에서만 동작

  • 트랜잭션이 완료되어야 함

  • 트랜잭션 수행시간이 elapsed 보다 커야 함 (또는 생략)

Hook 모듈과 함수가 연계될 때 파라미터를 주고 받아야 하는 경우가 있다.

  • Hook 모듈에서 S3 업로드 경로를 고객사 API에서 얻는다.

  • aws_s3 에서 해당 업로드 경로로 업로드한다.

이 때 변수(업로드 경로)를 소비할 함수에 도달할 때까지 중간에 얼마나 많은 체인함수가 있을지 알 수 없다. 이런 경우 X-M2X-Var- Prefix를 이용하면 함수체인을 통해 포워딩된다.

../_images/cf2.png

aws_s3 함수에서 소비할 변수가 함수체인으로 전달된다.

체인함수가 X-M2X-Var- 확장헤더를 소비했다면 반드시 삭제한다.

Note

변수와 함수는 1:1 맵핑을 원칙으로 한다. 따라서 동일한 값이 서로 다른 함수에서 필요한 경우 키/값 쌍을 각각 명시해주어야 한다.

체인함수 호출예외

일반적인 함수체인은 캐싱엔진을 통해 URL에 정의된 함수를 연쇄적으로 호출하는 구조이다. 여기서는 일부 예외적인 상황에 대해 설명한다.

cache 우회

체인함수에서 RT를 호출할 때 X-M2X-Function-Session 지시자를 통해 cache 정책을 우회할 수 있다.

Warning

내부 라우팅을 추적할 수 없으므로 설정이 아닌 약속된 코드레벨에서만 사용한다.

헤더

설명

bypass

이 요청을 바이패스하라

instant={n}

이 요청을 instant 바이패스하라

cache

이 요청을 캐싱하라

See also

X-M2X-Var- 확장헤더 참조

바이패스

클라이언트 요청을 캐싱엔진을 통하지 않고 체인함수로 바이패스 한다.

# vhosts.xml - <Vhosts><Vhost><DispatchMap>

<Function Name="pagespeed" Call="bypass" />

Call (기본: cache) 속성을 bypass 로 등록하면 캐싱엔진을 경유하지 않고, 클라이언트 요청이 체인함수로 바이패스 된다.

Warning

트래픽을 특정 함수로 위임하는 것으로 체인함수의 역할은 끝난다. 다시 말해 연속적인 체인함수를 연결할 수는 없다.

유입조절

Warning

이 기능은 bypass 로 호출되는 함수에서만 동작한다.

서버가 과부하 상태라면 함수의 서비스 품질을 보장하기 어렵다. 서비스 품질과 부하절감 차원에서 일시적으로 원본서버로 트래픽을 우회시키는 것이 더 나은 전략일 수 있다.

# vhosts.xml - <Vhosts><Vhost><DispatchMap>

<Function Name="pagespeed" Call="bypass">
  <Throttling Metric="cpu.deactive" Command="/throttling/" Key="cpu.deactive" Value="60" />
  <Throttling Metric="cpu.reactive" Value="40" />
</Function>
Throttling

세부 속성에 따라 함수 호출 유입량을 조정한다.

Metric

기본값

설명

cpu.deactive

60

함수를 호출하지 않는 조건을 설정한다.

cpu.reactive

40

( deactive 상태에서) 함수를 다시 호출하는 조건을 설정한다.

개별 함수에서 아래와 같은 형식으로 유입조절이 가능하다.

.../{function name}/........./{Command}/{Key=Value};{Key=Value}
Command

URL로부터 인지할 유입 조절 키워드

Key

함수의 유입조절 명령어

Value

함수의 유입조절 값

Note

함수체인 URL 명령으로는 reactive 가 지원되지 않는다. 왜냐하면 URL 명령은 해당 트랜잭션에서만 유효하기 때문에 해당 요청이 함수로 전달될지, 바이패스될지만 결정하면 되기 때문이다.

함수생략

모든 함수는 공통적으로 nocall 이라는 명령어를 가진다.

/sample.jpg/dims/nocall

캐싱엔진은 함수 호출시점에 /{함수호출}/nocall 호출이 감지되면 함수를 삭제한다. 위 예제의 경우 함수체인은 다음 순서로 해석한다.

  1. 캐싱엔진이 /sample.jpg/dims/nocall 로 캐싱키 생성

  2. 함수 호출 시점에 /dims/nocall 제거

  3. 잔여 URL인 /sample.jpg 에서 함수가 명시되지 않았다면 원본 호출

Warning

nocall 은 다른 함수의 파라미터처럼 전달될 수 있어 가능한 원본 URL 바로 뒤에 위치시킨다.

https://.../pagespeed/nocall/xcdr/.../dims/...

proxy 함수와 같이 사용되는 경우라면 반드시 proxy 뒤에 위치해야 한다.

https://.../proxy/src/.../pagespeed/nocall/dims/...

확장자 제외

체인함수가 처리할 수 없는 확장자에 대해 호출받고 싶지 않다면 확장자 리스트를 등록한다.

# vhosts.xml - <Vhosts><Vhost><DispatchMap>

<Function Name="pagespeed" ExclusionByExtensions="jpg, jpeg, png, bmp, webp, svg, icon" />

아래와 같이 확장자가 조건에 매칭된다면 함수생략 과 동일하게 처리된다. 아래 예제는 사용법은 다르지만 결과적으로 원본 파일을 그대로 서비스하게 된다.

# 캐싱키: /sample.jpg, 원본요청: /sample.jpg, 함수호출: 없음
/sample.jpg

# 캐싱키: /sample.jpg/pagespeed/nocall, 원본요청: /sample.jpg, 함수호출: 없음/nocall로 제거
/sample.jpg/pagespeed/nocall

# 캐싱키: /sample.jpg/pagespeed/default, 원본요청: /sample.jpg, 함수호출: 없음/확장자 조건으로 제거
/sample.jpg/pagespeed/default

Note

Mozilla에서 분류한 Common MIME types 중 대표적인 확장자는 다음과 같다.

  • 페이지 (CGI 관련 제외): html, htm, json, xhtml, xml

  • 프론트엔드: js, css, woff2, woff

  • 이미지: jpeg, jpg, png, gif, svg, ico, webp, avif, tiff, bmp

  • 비디오/오디오: mp4, ogg, avi, ts, webm, mpeg, flac, mp3, wav, aac

  • 문서: docx, xlsx, pptx, pdf, doc, xls, ppt, csv, log, txt, m3u8

  • 기타: zip, tar, rar, bin, jar, gz, 7z

라우팅 변경 debug

디버깅 용도로 RT <-> Core 간의 라우팅을 변경해야 하는 경우가 있다.

RT -> Core 로의 라우팅은 다음 설정으로 변경하고, 재가동해주어야 반영된다.

# server.xml - <Server><Cache>

<RemoteFunctionAddr>127.0.0.1:8585</RemoteFunctionAddr>

Core -> RT 로의 라우팅은 다음 설정으로 변경 가능하다.

# setting.json - env.rt.funtion

route: {
  remote: "127.0.0.1:8585",
  local: "127.0.0.1"
}

Note

재정의된 Core 포트는 체인함수 디스패치 맵remote0 포트로 지정되며 이후 1씩 더하여 사용한다.

체인함수 에러처리

체인함수마다 각기 다른 에러상황과 예외처리 정책이 달라 응답코드로 판단할 수 없다.

# 원본콘텐츠를 클라이언트에서 수용할 수 없다면 오류발생시 415로 응답한다.
HTTP/1.1 415 Unsupported Media Type
X-M2X-Function-Error: failparse

# 원본콘텐츠를 클라이언트에서 수용할 수 있다면 오류발생시 원본을 그대로 응답한다.
HTTP/1.1 200 OK
X-M2X-Function-Error: unknowntype

에러발생시 체인함수는 X-M2X-Function-Error 헤더를 통해 에러를 응답하며, 이 값은 origin.logx-sc-chain-error 필드에 기록된다.

체인함수 로그

체인함수의 정상동작은 access.logorigin.log 를 통해 증명 가능해야 한다.

로그취합과 기록방법을 가이드한다.

/log/write/ API

체인함수에서 발생한 트랜잭션 또한 access.logorigin.log 취합되어야 한다.

Note

RT 는 체인함수가 로그를 기록할 수 있도록 API를 제공한다.

  • POST /log/write/access?vhost={가상호스트}

  • POST /log/write/origin?vhost={가상호스트}

다음은 API 사용 주의사항이다.

  • Body 데이터는 1MB를 넘지 않는다.

  • 각 로그라인은 반드시 \n 으로 끝나야 한다.

  • 로그의 1,2번째 필드인 date , time 기재하지 않는다. ( RT 일괄부여)

기대할 수 있는 응답은 다음과 같다.

200 OK

정상 기록됨

404 Not Found

로그를 기록할 가상호스트를 찾을 수 없음

413 Request Entity Too Large

Body데이터가 너무 큼

dims 만으로 구성된 함수체인 호출을 통해 로그를 상세히 설명한다.

https://foo.com/sample.jpg/dims/resize/90/dims/quality/50/dims/grayscale/true

access.log

다음은 편의상 열 단위로 정렬한 accces.log 로그이다.

date          time     s-ip      cs-method  cs-uri-stem                                                    cs-uri-query s-port cs-username c-ip      cs(User-Agent)        sc-status sc-bytes time-taken cs-referer sc-resinfo cs-range sc-cachehit cs-acceptencoding session-id sc-content-length time-response x-transaction-status x-fallback x-ctx-id
2022-07-26    16:05:53 127.0.0.1 GET        /sample.jpg                                                    -            80     -           127.0.0.1 PostmanRuntime/7.29.0 200       21676    174        -          http       -        TCP_MISS    -                 4          21113             174           c                    -          5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26    16:05:53 127.0.0.1 GET        /sample.jpg/dims/resize/90                                     -            80     -           127.0.0.1 PostmanRuntime/7.29.0 200       9551     177        -          http       -        TCP_MISS    -                 3          9000              177           c                    -          5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26    16:05:53 127.0.0.1 GET        /sample.jpg/dims/resize/90/dims/quality/50                     -            80     -           127.0.0.1 PostmanRuntime/7.29.0 200       8991     181        -          http       -        TCP_MISS    -                 2          8441              181           c                    -          5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26    16:05:53 127.0.0.1 GET        /sample.jpg/dims/resize/90/dims/quality/50/dims/grayscale/true -            80     -           127.0.0.1 PostmanRuntime/7.29.0 200       8790     4463       -          http       -        TCP_MISS    gzip+deflate+br   1          8441              4462          c                    -          5d82b102-cfed-4e2c-90bd-985778b63067
  • cs-uri-stem URL함수가 단계별로 제거되며, 클라이언트 요청은 제일 마지막에 기록된다.

  • c-ip 클라이언트 IP가 기록된다.

  • cs(User-Agent) 클라이언트 User-Agent 가 기록된다.

  • x-ctx-id 동일한 컨텍스트 ID가 기록된다.

Note

함수체인은 항상 RT 에 의해 분기되기 때문에 특별한 경우가 아니라면 /log/write/access API를 호출하는 일은 없다.

origin.log

다음은 편의상 열 단위로 정렬한 origin.log 로그이다.

date       time     cs-sid cs-tcount c-ip          cs-method s-domain      cs-uri                                     s-ip          sc-status cs-range sc-sock-error sc-http-error sc-content-length cs-requestsize sc-responsesize sc-bytes time-taken time-dns time-connect time-firstbyte time-complete cs-reqinfo cs-acceptencoding sc-cachecontrol s-port sc-contentencoding session-id session-type x-sc-chain-error x-sc-chain-info time-sock-creation x-cs-retry x-cs-extra-field time-request x-ctx-id
2022-07-26 16:05:53 4      1         192.168.0.135 GET       192.168.0.144 /sample.jpg                                192.168.0.144 200       -        -             -             2369132           142            336             2369132  21         0        0            1              20            http       -                 -               80     -                  4          cache        -                -               0                  n          -                16:05:53.369 5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26 16:05:53 3      1         127.0.0.1     GET       127.0.0.1     /sample.jpg                                127.0.0.1     200       -        -             -             21113             574            563             21113    175        0        0            175            1             http       -                 -               80     -                  3          dims,cache   -                -               0                  n          -                16:05:53.367 5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26 16:05:53 2      1         127.0.0.1     GET       127.0.0.1     /sample.jpg/dims/resize/90                 127.0.0.1     200       -        -             -             9000              605            551             9000     179        0        0            178            1             http       -                 -               80     -                  2          dims,cache   -                -               0                  n          -                16:05:53.366 5d82b102-cfed-4e2c-90bd-985778b63067
2022-07-26 16:05:53 1      1         127.0.0.1     GET       127.0.0.1     /sample.jpg/dims/resize/90/dims/quality/50 127.0.0.1     200       -        -             -             8441              641            550             8441     183        0        0            182            1             http       -                 -               80     -                  1          dims,cache   -                -               0                  n          -                16:05:53.364 5d82b102-cfed-4e2c-90bd-985778b63067
  • session-type 함수호출자 정보

    # dims함수 구동을 위한 cache 함수호출
    dims,cache
    
    # cache함수 (원본호출)
    cache
    
  • x-sc-chain-error 함수실행 중 에러 메시지. 다중에러의 경우 구분자는 콤마.

  • x-sc-chain-info 함수 정보 메시지

  • x-ctx-id 동일한 컨텍스트 ID가 기록된다.

aws_s3 와 같이 독립적인 subflow , 또는 고객사 API 서버 연동등 클라이언트에게 노출되지 않는 트랜잭션은 모두 origin.log 에 기록되어야 한다.

  • subflow 트랜잭션이 완료되면 origin.log 형식에 맞추어 /log/write/origin API를 호출한다.

  • RTcache 를 거치치 않기 때문에 session-type 값에는 함수이름(예를 들어 aws_s3 )만 기록한다.

체인함수 Range 처리

HTTP 표준은 Range 접근을 허용하고 있으며 cache 는 다음과 같이 아직 다운로드되지 않은 영역에 대한 Range 접근을 허용한다.

../_images/cf3.png

Cache는 다중 다운로드에 의한 분할 캐싱을 지원한다.

하지만 체인함수는 기본적으로 Range 를 처리하지 않는다. dims 함수를 예로 들면 Range 처리를 위해 여러번 이미지를 변환하는 것보다 최초의 동작을 기다리는 편이 효과적이기 때문이다.

../_images/cf4.png

DIMS는 최초 다운로드에 의해서만 완성된다.

체인함수 Range 허용설정

체인함수가 반드시 Range 를 처리해야 하는 기능요건이라면 체인함수 등록시 디스패치 맵의 Partial 속성을 활성화한다.

# vhosts.xml - <Vhosts><Vhost><DispatchMap>

<Function Name="xcdr" Keyword="videopt" Partial="on" />

체인함수의 Range 지원은 단순히 기능구현의 어려움에 그치지 않는다. 체인함수가 캐싱엔진에 기반하여 동작하는만큼 파일 섞임으로 인해 무결성이 깨질 수 있는 환경에 노출된다는 것을 의미한다.

체인함수와 캐시 갱신

HTTP의 304 Not Modified 메커니즘은 콘텐츠를 이미 소유한 클라이언트에게 서버가 변경없음 을 알려주는 우아한 메커니즘이다. 체인함수가 이를 적절히 구현하지 않을 경우, TTL 만료 시점에 항상 콘텐츠를 재가공하게 되어 과도한 리소스를 낭비하는 상황이 벌어질 수 있다.

Note

아래 다이어그램의 cache1 , cache2 는 같은 cache 함수이나 쉬운 설명을 위해 각각으로 구분하였다.

../_images/mermaid-diagram-2023-03-20-182837.png

전형적인 TCP_MISSTCP_HIT 시나리오

원본 304 Not Modified 전파

모든 체인함수는 cache 의 원본으로 동작한다. 따라서 If-Modified-SinceIf-None-Match 등 표준 헤더를 이용해 유효시간을 연장한다.

../_images/mermaid-diagram-2023-03-20-183351.png

캐싱된 객체가 변경되지 않았다면 TCP_REFRESH_HIT 로 기록된다.

대표적으로 원본 이미지가 변경되지 않았다면 dims 함수로 가공된 이미지도 변경되지 않았다고 판단할 수 있다. 따라서 함수체인은 304 Not Modified 전파 메커니즘을 기본으로 동작한다. 함수체인이 구현/검수해야 하는 If-Modified-Since 메커니즘를 순서대로 상세히 나누어 알아보자.

TCP_MISS 시나리오

Note

컨텍스트

  • 최초 요청

  • 이전 캐싱된 콘텐츠가 HardPurge 된 경우

캐싱되어 있지 않은 콘텐츠라면 cacheIf-Modified-Since 헤더를 명시하지 않고 요청한다.

../_images/mermaid-diagram-20230719153100.png

체인함수는 콘텐츠를 가공한 뒤 200 OK 로 응답한다. 이때 Last-Modified 헤더는 반드시 원본의 값을 참조해서 응답해야 한다.

TCP_REFRESH_HIT 시나리오

Note

컨텍스트

  • 이전 캐싱된 콘텐츠의 ttl 이 만료된 경우

  • 이전 캐싱된 콘텐츠가 Expire 된 경우

200 OK 로 정상 캐싱된 상태라면 cacheIf-Modified-Since 헤더를 명시하여 갱신을 묻는다.

../_images/mermaid-diagram-20230719153220.png

체인함수는 이에 대해 판단할 수 없다. 따라서 반드시 원본의 변경여부를 체크해야 한다. 원본이 변경되지 않았다면 (= 304 Not Modified ) 동일하게 304 응답코드로 응답한다.

Note

cache304 를 수신하면 캐싱된 객체의 ttl 만을 연장한다.

TCP_REFRESH_MISS 시나리오

Note

컨텍스트

  • 이전 캐싱된 콘텐츠의 원본 콘텐츠가 변경된 경우

  • 이전 캐싱된 콘텐츠가 Purge 된 경우. 이 경우 cacheIf-Modified-Since 헤더를 전송하지 않지만 TCP_REFRESH_MISS 로 판정한다.

TCP_REFRESH_HIT 시나리오 와 요청은 동일하지만 원본이 200 OK 로 응답한다.

../_images/mermaid-diagram-20230719153331.png

응답시나리오는 TCP_MISS 시나리오 와 동일하다. 200 OK 와 원본의 Last-Modified 헤더 값을 참조하여 응답한다.

Note

원본에서 콘텐츠 삭제 404 , 오류 500 로 응답하는 것은 정상적인 상황으로 캐싱 콘텐츠가 교체된다.

PHANTOM 객체 동작과 객체갱신

다음 환경이라면 클라이언트 응답의 대부분은 304 Not Modified 가 된다.

  • 원본이 거의 변경되지 않음

  • 콘텐츠 대부분이 CDN 캐싱되어 있음

  • M2의 메모리 가용량이 제한적임

이런 경우 phantom 객체를 활성화하면 효과적이다.

../_images/mermaid-diagram-20230503172151.png

인바운드 트래픽 증가없이 PHANTOM 객체만으로 304 응답이 가능하다.

원본이 304 가 아닌 변경에 대한 응답을 줄 경우 객체가 교체되어 서비스된다.

../_images/mermaid-diagram-20230503164126.png

원본이 변경되었다면 PHANTOM 객체와 일반객체가 교체된다.

데이터 접근요청이 발생한다면 PHANTOM 객체는 소거되고 재캐싱이 발생한다.

../_images/mermaid-diagram-20230503164132.png

Important

위 시나리오는 함수체인에서 연쇄적으로 발생한다. 따라서 이미지 재가공 부하등 연산부하를 낮추는 효과가 있다.

체인함수의 ETag 헤더 지원

원본서버가 304 Not Modified 를 수행할 수 없는 환경이라면 원본 304 Not Modified 전파 방식만으로는 충분치 않다. 그 반대로 원본 콘텐츠가 변경되지 않았더라도, 설정변경으로 인해 캐싱 콘텐츠를 교체해야 하는 경우도 이에 해당한다.

Note

체인 함수가 ETag 를 생성/제공 한다는 것은 콘텐츠 생성에 대해 전적인 책임을 가진다는 의미이다. 표준 개발 가이드는 다음과 같다.

  • ETag 는 해쉬된 문자열로, 콘텐츠 생성에 영향을 주는 요소들이 포함되어야 한다. 다음은 필수 요소이다.

    • 콘텐츠 Body

    • 체인함수의 설정전체

    • 호출 명령어

  • 위 조건이 결함 없이 모두 동일하다면 수행 전 304 Not Modified 를 클라이언트에게 응답할 수 있다.

    • 검수 단계에서는 반드시 필수 요소의 변경을 통해 다른 ETag 가 도출됨을 보장해야 한다.

    • 그 밖의 시드가 제공된다면 함수 개발자는 이를 검수 담당자에게 고지해야 한다.

  • pagefxtimeout 기능처럼 임시 결과물를 제공하는 경우 다음 규칙을 따른다.

    • 미완성 결과물을 유지하지 않는다. (= 200 OK 로 응답한다.)

    • ETag 값을 통해 미완성 또는 중간 결과물임을 구분할 수 있어야 한다.

    • 해쉬의 시드로 epoch 시간등을 추가하거나, suffix를 추가할 수 있다.

  • 의도치 않은 304 Not Modified 등으로 갱신이 안되는 경우 캐싱콘텐츠 무효화 API 를 호출하여 갱신을 강제할 수 있다.

pagefx 함수는 대표적인 ETag 기반 함수로, 원본서버가 데이터베이스로부터 직접 질의한다는 이유로 304 처리를 생략하는 경우가 왕왕있다.

../_images/mermaid-diagram-2023-03-20-185719.png

pagefx 함수가 생성한 ETagcache1 이 기억한다.

원본서버가 항상 200 OK 로 응답하는 경우라도 pagefx 는 Body와 설정이 같다면 304 Not Modified 를 응답할 수 있다.

../_images/mermaid-diagram-2023-03-20-193231.png

ETag 는 항상 같은 규칙으로 생성된다.

ETag 로 동작하기 위해서는 체인함수 디스패치 맵Refresh 속성을 etag 로 등록해 주어야 한다.

# vhosts.xml - <Vhosts><Vhost><DispatchMap>

<Function Name="pagefx" Keyword="pagefx" Refresh="etag" />