CloudFront๋ฅผ ๊ฑท์ด๋ด๊ณ Cloudflare๋ก. Worker + R2 CDN ์ ํ ์ฝ์ง๊ธฐ
- #Cloudflare
- #R2
- #Worker
- #CloudFront
- #CDN
- #AWS
- #Cache
์๋ ํ์ธ์. ๋ ธ๋จธ์ค์์ ๋ฐฑ์๋ ๊ฐ๋ฐ์ ํ๊ณ ์๋ ์ง์น๋ณด์ ๋๋ค.
์ผ๋ง ์ ์ฐฌํฌ๋์ด CloudFront + Lambda@Edge to Cloudflare Worker + R2 PoC ๊ธ์์ โAWS ๋ฏธ๋์ด ์คํ์ Cloudflare๋ก ์ฎ๊ธธ ์ ์๋๊ฐโ๋ผ๋ ์ง๋ฌธ์ ๋ต์ ๋ด๋ ค์ฃผ์ จ์ต๋๋ค. ๊ฒฐ๋ก ์ ์ด๋ฏธ์งยท์ผ๋ฐ VOD๋ ์ฎ๊ธธ ๋งํ๊ณ , 4KยทAES-128์ MediaConvert๋ฅผ ์ ์งํ๋ ํ์ด๋ธ๋ฆฌ๋์์ต๋๋ค.
์ด ๊ธ์ ๊ทธ PoC์ ํ์ํธ์ ๋๋ค. โ์ฎ๊ธธ ์ ์๋คโ์ โ์ด๋ฏธ ํธ๋ํฝ์ด ํ๋ฅด๊ณ ์๋ ์ด์ ์๋น์ค๋ฅผ ์ ๋๊ณ ์ฎ๊ธด๋คโ๋ ๋ค๋ฅธ ์ด์ผ๊ธฐ์๊ณ , ๊ทธ ์ฌ์ด์์ ์ ๊ฐ ๋ฐ์ ์ฝ์ง๋ค์ ์ ๋ฆฌํ์ต๋๋ค.
TL;DR
- ๊ฐ๋ฅํ๊ฐ? ์ ๋๊ธฐ๊ณ ์ด๋ป๊ฒ?: ํ์ผ URL์ RDSยทFirestore ์ฌ๊ธฐ์ ๊ธฐ์ ์ ์ฅ๋ผ ์์ต๋๋ค. ์ ๊ท ํ์ผ๋ง R2์ฉ ๋ณ๋ ๋๋ฉ์ธ์ผ๋ก ๋นผ๋๋ฉด, ๋์ค์ ์์ ํ R2๋ก ๋์ด๊ฐ ๋ ์ด๋ฏธ ์ ์ฅ๋ URL์ ์ ๋ถ ์ฐพ์ ๋ฐ๊ฟ์ผ ํฉ๋๋ค. ๊ทธ๋์ URL์ ์๋์ง ์๊ณ , S3 โ R2 ๋๊ธฐํ๋ฅผ ๋จผ์ ๋๋ฆฐ ๋ค DNS๋ง Cloudflare๋ก ๋ฐ๊ฟ ๋ค์์ ์ค๋ฆฌ์ง๋ง ๊ฐ์๋ผ์ฐ๋ ์ชฝ์ผ๋ก ๊ฐ์ต๋๋ค.
- Cloudflare ์บ์๋ CloudFront์ฒ๋ผ ๋์ํ์ง ์๋๋ค: ๋น์ฉ์ ์ก์ผ๋ ค๋ฉด ์บ์๋ก R2 ์ ๊ทผ์ ์ค์ฌ์ผ ํ๋๋ฐ, CloudFront์์ ์๋ ์บ์ ์์์ด Cloudflare์ ๊ทธ๋๋ก ํตํ์ง ์์์ต๋๋ค. ๋ฌธ์์ ์ค์ ๋์์ ์ง์ ์ฐ์ด๋ณด๋ฉฐ ์บ์ ๊ตฌ์กฐ๋ฅผ ๋ค์ ์ตํ์ต๋๋ค.
- egress 0์์ด ์ ๋ถ๊ฐ ์๋๋ค: R2๋ ๋ฐ์ดํฐ ์ ์ก(egress)์ ๊ณต์ง์ง๋ง, ํ์ผ์ ์ฝ๋ ์ ๊ทผ(Class B operation) ์์ฒด์๋ ๊ณผ๊ธ๋ฉ๋๋ค. Worker ์บ์๋ก R2 ๋๋ฌ ํ์๋ฅผ ์ค์ด์ง ๋ชปํ๋ฉด egress๋ฅผ 0์์ผ๋ก ๋ง๋ค์ด๋๊ณ ๋ ์ ํ ์ด๋์ด ์ฌ๋ผ์ง๋๋ค.
- private vs public ๋๋ ๋ง: ์ฌ์ฉ์๋ณ ๊ถํ์ด ๋ค๋ฅธ ์ฝํ
์ธ ๋ผ ํด๋ผ์ด์ธํธ์๋
Cache-Control: private์ผ๋ก ์๋ตํด์ผ ํฉ๋๋ค. CloudFront๋ ์ค๋ฆฌ์ง์ดprivate์ ์ค๋ ์์์ ์บ์ฑํด์คฌ๊ธฐ์ Cloudflare๋ ๊ทธ๋ฌ๋ ค๋ ํ๋๋ฐ, Worker ์บ์(caches.default)๋private์๋ต์ ์กฐ์ฉํ ์ ์ฅ ๊ฑฐ๋ถํ์ต๋๋ค. ๊ฒฐ๊ตญ ์ ์ฅํ ๋ public, ์๋ตํ ๋ ๋ค์ private์ผ๋ก ๋๋๋ฆฌ๋ ๋ฐฉ๋ฒ์ผ๋ก ํ์์ต๋๋ค.
๋ชฉ์ฐจ
- PoC์ ์ค์ ์ฌ์ด์ ๊ฐ๊ทน
- ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต
- ์ฝ์ง 1 โ Cloudflare ์บ์๋ CloudFront์ฒ๋ผ ๋์ํ์ง ์์๋ค
- ์ฝ์ง 2 โ egress 0์์ ํจ์ , R2๋ ์ ๊ทผํ๋ฉด ๋์ด๋ค
- ์ฝ์ง 3 โ private์ผ๋ก ์๋ตํด์ผ ํ๋๋ฐ ์บ์๋ public๋ง ์ ์ฅํ๋ค
- Worker ํ๋์ ๋๋ฌ ๋ด์ ์์ํ ์ฒ๋ฆฌ๋ค
- CloudFront ํฌ๋งท ๊ทธ๋๋ก ๊ฒ์ฆํ๊ธฐ
- ๋ง์น๋ฉฐ
PoC์ ์ค์ ์ฌ์ด์ ๊ฐ๊ทน
์ฐฌํฌ๋ PoC์์ ๋ค์๊ณผ ๊ฐ์ ๊ฒ๋ค์ ๋ฏธ๋ฆฌ ์ ์ ์์์ต๋๋ค.
- R2๋ S3 SDK๋ฅผ ๊ทธ๋๋ก ์ธ ์ ์๋ค.
- Worker๋ Lambda@Edge๊ฐ ํ๋ ์ผ(์ฟ ํค ๋ฐ๊ธ, Cache-Control ๋ถ์ฌ)์ ๋์ฒดํ ์ ์๋ค.
- egress 0์ ๋๋ถ์ ๋น์ฉ ์ํฉํธ๊ฐ ํฌ๋ค.
โ์ฎ๊ธธ ์ ์๋๊ฐโ์ ๋ํ ๋ต์ ์ด๊ฑธ๋ก ๋์จ ์ ์ ๋๋ค. ์ ๋ชซ์ ์ด ๊ฒฐ๋ก ์ ์ด๋ฏธ ์ฌ์ฉ์ ํธ๋ํฝ์ด ํ๋ฅด๊ณ ์๋ ์ด์ ๋ฏธ๋์ด ์คํ์ ์ค์ ๋ก ํ์ฐ๋ ์ผ์ด์์ต๋๋ค. ๊ฐ๋ ์ ๊ฒ์ฆํ๋ ๊ฒ๊ณผ, ๊ทธ ๊ฐ๋ ์ ํธ๋ํฝ ๋๊น ์์ด ์ด์์ ํ์ฐ๋ ๊ฒ์ ๊ฒฐ์ด ๋ค๋ฅธ ๋ฌธ์ ๋ผ, ์ค์ ๋ก ์ฎ๊ธฐ๋ ๊ณผ์ ์์ ์ด๋ฐ ๊ฒ๋ค์ ํ๋์ฉ ๋ง์ฃผํ์ต๋๋ค.
- ์ด๋ค ์์๋ก ๋ฐฐํฌํด์ผ ๋ค์ดํ์ ์์ด ๋์ด๊ฐ๋๊ฐ โ ๋ฐฐํฌ ์ ๋ต
- ์ด๋ฏธ ์์ฌ ์๋ ๊ธฐ์กด ํ์ผ ์ ์ฒด๋ฅผ ์ด๋ป๊ฒ R2๋ก ์ฎ๊ธฐ๋๊ฐ
- RDSยทFirestore ์ฌ๊ธฐ์ ๊ธฐ์ ์ ์ฅ๋ URL์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋๊ฐ
- โ์บ์๊ฐ ์ง์ง๋ก ๋จน๊ธด ํ๋?โ ์ฒ๋ผ, ์ค์ ํธ๋ํฝ์์๋ง ํ์ธ๋๋ ๊ฐ์ ๋ค
์ด ๊ธ์ ๋๋ถ๋ถ์ ์ด๋ ๊ฒ ๋ธ๋ ค ์จ ๊ฒ๋ค๊ณผ์ ์จ๋ฆ์ ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต
๊ฐ์ฅ ๋จผ์ ์ธ์ด ๊ณํ์ ๋จ์ํ์ต๋๋ค.
โ์์ผ๋ก ์ ๋ก๋๋๋ ํ์ผ์ R2๋ก ์ฌ๋ฆฌ๊ณ , ์ฃผ์๋ R2์ฉ ๋ณ๋ ๋๋ฉ์ธ์ผ๋ก ์ ์ฅํ์. ๊ธฐ์กด ํ์ผ์ ๋์ค์ ์ฎ๊ธฐ๋ฉด ๋์ง.โ
๊ทธ๋ฐ๋ฐ ์ด๊ฒ ์๊ทผํ ๋ถ์ฑ๊ฐ ๋์ต๋๋ค. ์ ๊ท ํ์ผ๋ง ๋ณ๋ ๋๋ฉ์ธ์ผ๋ก ์ ์ฅํด๋๋ฉด, ๋์ค์ ๊ธฐ์กด ํ์ผ๊น์ง R2๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ ๋ ํ ์๋น์ค ์์ ๋ ๊ฐ์ ๋ฏธ๋์ด ๋๋ฉ์ธ์ด ์์ด๊ฒ ๋ฉ๋๋ค. ๊ฒ๋ค๊ฐ ์ธํ๋ผ ๊ณํ์ ์ต์ข ์ ์ผ๋ก๋ R2๊ฐ ๊ธฐ์กด ๋๋ฉ์ธ์ ๊ทธ๋๋ก ๋๊ฒจ๋ฐ์ ์๋นํ๊ฒ ๋ ์ ์์์ต๋๋ค. ๊ทธ๋ ๊ฒ ๋๋ฉด ์ ์จ ๋๋ ๋ ๋ณ๋ ๋๋ฉ์ธ URL๋ค์ ๋ค์ ์ ๋ถ ๋๋๋ ค์ผ ํฉ๋๋ค.
๋ฌธ์ ๋ ๊ทธ URL๋ค์ด ํ ๊ณณ์ ์์ง๋ ์๋ค๋ ์ ์ด์์ต๋๋ค. RDS์๋, Firestore์๋ ํฉ์ด์ ธ ์๊ณ , ์ฝํ ์ธ ์ข ๋ฅ๋ง๋ค ์ ์ฅ ์์น์ ํฌ๋งท์ด ๋ฌ๋์ต๋๋ค. ์ด๊ฑธ ์ ๋ถ ์ฐพ์ ์์์ ์ผ๋ก ๋ฐ๊พธ๋ ๊ฑด ๊ทธ ์์ฒด๋ก ๋ ํ๋์ ์ํํ ๋ํ ๋ง์ด๊ทธ๋ ์ด์ ์ด์์ต๋๋ค.
๊ทธ๋์ ๋ฐฉํฅ์ ๋ค์ง์์ต๋๋ค. โURL์ ์ฒ์๋ถํฐ ๊ฑด๋๋ฆฌ์ง ์๋๋ค.โ ์ ๊ท ํ์ผ๋ ๋ณ๋ ๋๋ฉ์ธ์ผ๋ก ๋๋์ง ์๊ณ , ๊ธฐ์กด ๋๋ฉ์ธ์ ๊ทธ๋๋ก ์ฐ๋ ๋ค์์ ์ค๋ฆฌ์ง๋ง ๋ฐ๊พธ๋ ์ชฝ์ผ๋ก์.
- ๊ธฐ์กด ํ์ผ์ ํต์งธ๋ก R2๋ก ์ฎ๊ธด๋ค. ์ด๋ฏธ S3์ ์์ฌ ์๋ ํ์ผ์ Cloudflare๊ฐ ์ ๊ณตํ๋ ๋ง์ด๊ทธ๋ ์ด์ ๋๊ตฌ์ธ Super Slurper๋ก R2์ ๋ณต์ฌํ์ต๋๋ค. ์ฐ๋ฆฌ ์ชฝ ํ์ผ์ ๋๋ถ๋ถ 10MB ๋ฏธ๋ง(์ฃผ๋ก ์ด๋ฏธ์ง)์ด๋ผ ํ์ผ๋น 2~3์ด๋ฉด ๋ณต์ฌ๊ฐ ๋๋ฌ๊ณ , ์ด ๋์ ์๋น์ค ํธ๋ํฝ์ ์ฌ์ ํ 100% CloudFront โ S3๋ก ํ๋ฆ ๋๋ค.
- R2 โ S3 ์ญ๋ฐฉํฅ sync๋ฅผ ๋จผ์ ๊น๊ณ , ๊ทธ๋ค์ ์ ๋ก๋ ๋์์ S3์์ R2๋ก ๋ฐ๊พผ๋ค. ์์๊ฐ ์ค์ํ์ต๋๋ค. ์ ๋ก๋๋ฅผ R2๋ก ๋๋ฆฌ๋ ์๊ฐ์๋ DNS๋ ์์ง CloudFront(=S3 ์ค๋ฆฌ์ง)๋ฅผ ๋ณด๊ณ ์์ผ๋, R2์ ์ฌ๋ผ์จ ํ์ผ์ด S3์๋ ์์ด์ผ ํ๋ฉด์ ๋น๋๋ค. ๊ทธ๋์ R2์ ํ์ผ์ด ์๊ธฐ๋ฉด ๊ณง๋ฐ๋ก S3๋ก ๋๋๋ ค ๋ณต์ ํ๋ sync๋ฅผ ๋จผ์ ๋ฐฐํฌํด๋์ต๋๋ค. ์ด sync๋ ์ด๋ฏธ S3์ ๊ฐ์ ํ์ผ์ด ์์ผ๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ก ํด์, ์์ Super Slurper๋ก ์ฎ๊ฒจ๋ ํ์ผ๊ณผ ๋ถ๋ชํ์ง ์๊ฒ ํ์ต๋๋ค. R2 โ S3 ๋ณต์ ๋ ๋๋ต 6์ด์ฏค ๊ฑธ๋ ธ์ต๋๋ค.
- ์ด ์งง์ ์ฐฝ ์์์ DNS๋ฅผ CloudFront์์ Cloudflare๋ก ๋๊ธด๋ค. ์ ํ ์ฐฝ ๋์์๋ ์ ์ ๊ฐ ์ด๋ฏธ์ง๋ฅผ ์ฌ๋ฆฐ ๋ค ๊ทธ๊ฒ ๋ณด์ด๊ธฐ๊น์ง 6์ด ์ ๋ ์ง์ฐ์ด ์๊ธธ ์ ์์์ต๋๋ค. ์ฅ์ ๋ ์๋๊ณ , ์๋ก๊ณ ์นจ์ด๋ ์ฑ ๋ด ์ฌ์๋๋ก ํก์๋๋ ์์ค์ด์์ต๋๋ค. ๋ง์นจ DNS ๋ ์ฝ๋์ TTL์ด 60์ด๋ผ, ์ค๋ฆฌ์ง์ ๋๊ธด ๋ค ์ ์ธ๊ณ ๋ฆฌ์กธ๋ฒ๊ฐ ์ ์ฃผ์๋ฅผ ๋ฌผ์ด๊ฐ๋ ๋ฐ ๊ธธ์ด์ผ 1๋ถ์ด๋ฉด ์ถฉ๋ถํ์ต๋๋ค.
- DNS๊ฐ ๋์ด๊ฐ๋ฉด Worker + R2๊ฐ ์ง์ ์๋นํ๋ค. ๋๋ฉ์ธ์ ๊ทธ๋๋ก๋ผ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ URL์ ํ๋๋ ๋ฐ๋์ง ์๊ณ , ๋ค์์ ์ค๋ฆฌ์ง๋ง ๊ฐ์๋ผ์์ง ์ ์ ๋๋ค.
์ด R2 โ S3 ๋ฐฑ์ ๊ฒฝ๋ก๋ ๋กค๋ฐฑ ์ S3๊ฐ ์๋ณธ์ ๊ทธ๋๋ก ๊ฐ๊ณ ์๋๋ก ํ๊ธฐ ์ํ ์ฉ๋์ ๋๋ค. R2๋ก ๋์ด๊ฐ ๋ค ๋ฌธ์ ๊ฐ ์๊ฒจ๋ DNS๋ง ๋๋๋ฆฌ๋ฉด ๋ฉ๋๋ค. ์ ์ฒด ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆผ์ผ๋ก ๋ณด๋ฉด ์ด๋ ์ต๋๋ค.

์ฝ๊ธฐ ๊ฒฝ๋ก๋ Client โ Worker โ caches.default โ R2. ๋ฐฑ์
๊ฒฝ๋ก๋ R2์ ํ์ผ์ด ์๊ธฐ๋ฉด R2 ObjectCreated โ Cloudflare Queue โ consumer Worker โ AWS SQS โ Lambda โ S3๋ก ๋๋๋ ค ๋ณต์ ํฉ๋๋ค. ์ค์ consumer Worker๋ ์ด๋ ๊ฒ ์๊ฒผ์ต๋๋ค.
// R2 ObjectCreated โ SQS SendMessage (S3 ๋ฐฑ์
ํ)
export default {
async queue(batch: MessageBatch<R2EventNotification>, env: Env): Promise<void> {
for (const message of batch.messages) {
try {
await processMessage(message, env);
} catch (error) {
message.retry();
}
}
}
};
// MediaConvert ๊ฒฐ๊ณผ๋ฌผ์ฒ๋ผ ์ด๋ฏธ S3์ ์กด์ฌํ๋ prefix๋ ๋๋๋ฆด ํ์๊ฐ ์์ด ์ ์ธ
const EXCLUDED_PREFIXES: Record<string, string[]> = {
'fromm-channel-contents': ['fromm_channel/', 'live/']
// ...
};
์ฝ๋์์ ํน์ prefix๋ฅผ ์ ์ธํ๋ ๊ฑด MediaConvert ๋๋ฌธ์
๋๋ค. ์ฐฌํฌ๋ PoC์ ๊ฒฐ๋ก ๋๋ก, ์ธ์ฝ๋ฉ(MediaConvert)์ ์ฎ๊ธฐ์ง ์๊ณ AWS ๊ฒ์ ๊ทธ๋๋ก ์ฐ๊ธฐ๋ก ํ์ต๋๋ค. Cloudflare Stream์ด 4KยทAES-128 ๊ฐ์ ์ต์
์ ๋๋ถ๋ถ ์ง์ํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ๋์ ์
๋ก๋๋ R2๋ก ๋ฐ๊ฟจ์ด๋, MediaConvert๋ง์ ์์ธ๋ก ๊ฒฐ๊ณผ๋ฌผ์ ์ฌ์ ํ S3๋ก ์ถ๋ ฅํ๊ณ ๊ทธ๊ฑธ R2๋ก syncํ๋ ๋ฐฉํฅ์ ํํ์ต๋๋ค. ์ฆ MediaConvert ๊ฒฐ๊ณผ๋ฌผ์ ์ฒ์๋ถํฐ S3์ ์๋ณธ์ด ์์ผ๋, R2 โ S3 ๋ฐฑ์
๋์์์ ๋นผ๋ ๋ฉ๋๋ค. ์ EXCLUDED_PREFIXES๊ฐ ๊ทธ ์์ธ๋ฅผ ๊ฑธ๋ฌ๋ด๋ ๋ถ๋ถ์
๋๋ค.
@pulumi/cloudflare๊ฐ ์์ง R2 Event Notification ๋ฆฌ์์ค๋ฅผ ์ง์ํ์ง ์์, ์ด๋ฒคํธ ์๋ฆผ โ ํ ์ฐ๊ฒฐ๋ง ๋์๋ณด๋์์ ์๋์ผ๋ก ๊ฑธ์ด์ค์ผ ํ๋ ๊ฑด ๋ค์ด์์ต๋๋ค. IaC๋ก ๋ค ๊ฐ์ธ๊ณ ์ถ์์ง๋ง, ์ง์๋์ง ์๋ ๋ถ๋ถ์ ์ธ์ ํ๊ณ README์ โ์ฌ๊ธฐ๋ ์์ผ๋ก ์ค์ ํด์ผ ํจโ์ ๋ช
์ํด๋๋ ํธ์ ํํ์ต๋๋ค.
์ฝ์ง 1 โ Cloudflare ์บ์๋ CloudFront์ฒ๋ผ ๋์ํ์ง ์์๋ค
์ด๋ฒ ๋ง์ด๊ทธ๋ ์ด์ ์ ๊ฐ์ฅ ํฐ ๋ชฉํ๋ ๋น์ฉ ์ ๊ฐ์ด์์ต๋๋ค. Cloudflare์ egress๊ฐ ๋ฌด๋ฃ๋ผ๋ ์ ์ ์ต๋ํ ์ด๋ฆฌ๋ ๊ฒ ๋ชฉํ์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ egress๊ฐ ๊ณต์ง์ฌ๋ R2๋ ํ์ผ์ ์ ๊ทผํ ๋๋ง๋ค operation ๋น์ฉ์ด ๋ถ์ต๋๋ค. ์ค์ง์ ์ธ ๋น์ฉ์ ๊ฒฐ๊ตญ ์ฌ๊ธฐ์ ๋๋ค๊ณ ๋ดค๊ณ (์์ธํ ์ซ์๋ ๋ค์ ์ฅ์์ ๋ค๋ฃน๋๋ค), ๊ทธ๋์ ์บ์๋ก R2 ์ ๊ทผ ํ์๋ฅผ ์ต๋ํ ์ค์ด๋ ๊ฒ ์ด ์ ํ์ ํต์ฌ ๊ณผ์ ์์ต๋๋ค.
๋ฌธ์ ๋ โCloudFront๊ฐ ํด์ฃผ๋ ์๋น๊ณผ ์บ์ฑ์ Worker + R2์์ ์ด๋ป๊ฒ ๋๊ฐ์ด ์ฌํํ์ง?โ์๋๋ฐ, ์ฌ๊ธฐ์๋ถํฐ ์์์ด ์ด๊ธ๋ฌ์ต๋๋ค. ์บ์ ๊ตฌ์กฐ๋ฅผ ์กฐ์ฌํ๋ ์ค AI๊ฐ โ์๋ต์ Cache-Control: public์ ์ฃผ๋ฉด Cloudflare CDN์ด ์บ์ฑํด์ ๊ทธ๋ค์๋ถํฐ๋ Worker๊น์ง ์์ฒญ์ด ์ค์ง ์๋๋คโ๊ณ ์๋ ค์คฌ์ต๋๋ค. ๊ทธ๋ด๋ฏํด์ ๊ทธ๋๋ก ๋ถ์ฌ๋ดค๋๋ฐ, Worker๋ ๋งค ์์ฒญ ๊ณ์ ํธ์ถ๋์ต๋๋ค. ๋ค์ ํ์ธํด๋ณด๋ ๊ทธ๋ฐ ๋์์ ์์๊ณ , ์ด๊ฑธ ๋ถ์ก๊ณ ์ ๊น ํค๋งธ์ต๋๋ค. ๋ฌธ์์ ์ค์ ๋์์ ์ง์ ์ฐ์ด๋ณด๋ฉฐ ๊ฐ์ผ๊ฒ ๋ค๊ณ ๋ง์๋จน์ ๊ณ๊ธฐ์ด๊ธฐ๋ ํ์ต๋๋ค.
์ง์ ํ์ธํด๋ณด๋ Cloudflare์ caches.default๋ CloudFront์ฒ๋ผ โWorker ์๋จ์์ ์์์ ๊ฑธ๋ฌ์ฃผ๋ ์๋ CDN ์บ์โ๊ฐ ์๋์์ต๋๋ค. ์ด๊ฑด Worker ์ฝ๋ ์์์ ๋ด๊ฐ ์ง์ cache.match()๋ก ์กฐํํ๊ณ cache.put()์ผ๋ก ์ ์ฅํ๋ ์๋ ์บ์์
๋๋ค. ์บ์ ๋ด์ฉ์ด ์ ์ธ๊ณ ์ฃ์ง๋ก ์๋ ๋ณต์ ๋์ง๋ ์์ต๋๋ค.
๊ทธ๋ฌ๋๊น ์ค์ ๋ชจ๋ธ์ ์ด๋ ์ต๋๋ค.
Client โ Worker(์คํ๋จ) โ caches.default(match/put) โ R2
Worker๋ ์ด์ฐจํผ ๋งค ์์ฒญ ์คํ๋ฉ๋๋ค. ๋์ ๊ทธ ์์์ ์บ์๋ฅผ ์ ํ์ฉํ๋ฉด R2 ์ ๊ทผ์ ์ค์ด๋ ๊ตฌ์กฐ์ ๋๋ค. โWorker๋ฅผ ์ ๊ฑฐ์น๊ฒ ๋ง๋ ๋คโ๊ฐ ์๋๋ผ โWorker๋ ๊ฑฐ์น๋ R2๋ ์ ๊ฑด๋๋ฆฌ๊ฒ ๋ง๋ ๋คโ๊ฐ ๋ชฉํ์๋ ๊ฒ๋๋ค. ์ด ์ง์ ์์ ์ ๊ทผ ๋ฐฉ์์ด ์์ ํ ๋ฐ๋์์ต๋๋ค.
์ฝ์ง 2 โ egress 0์์ ํจ์ , R2๋ ์ ๊ทผํ๋ฉด ๋์ด๋ค
R2๋ฅผ ์ ํํ ์ด์ ๋ โegress ๋น์ฉ์ด ์๋คโ ์ ๋๋ค. CloudFront ์ฒญ๊ตฌ์์ 90% ์ด์์ด ๋ฐ์ดํฐ ์ ์ก ๋น์ฉ์ด์์ผ๋, ์ฌ๊ธฐ๊ฐ 0์์ด ๋๋ ๊ฑด ํฐ ์ํฉํธ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ ๋ ๊ทธ ๋ฌธ์ฅ์ ์ทจํด์ โR2 ์ ๊ทผ ์์ฒด๋ ๋์ด ๋ ๋คโ ๋ ๊ฑธ ํ๋์ ์๊ณ ์์์ต๋๋ค.
R2๋ egress๋ ๊ณต์ง์ง๋ง, ์คํผ๋ ์ด์
์๋ ๊ณผ๊ธํฉ๋๋ค. GetObject, HeadObject ๊ฐ์ ์ฝ๊ธฐ๋ Class B operation์ผ๋ก ๋ถ๋ฅ๋๊ณ , 2026๋
4์ ๊ธฐ์ค ๋ฐฑ๋ง ์์ฒญ๋น $0.36์
๋๋ค. ์ฌ๊ธฐ์ ์ง์ด๋ ๊ฒ, ์ด ๋จ๊ฐ๋ S3์ ๊ฑฐ์ ๊ฐ์ต๋๋ค. S3 Standard์ GET ์์ฒญ๋ ๋ฐฑ๋ง ๊ฑด๋น $0.40 ์์ค์ด๋ผ, ์คํ ๋ฆฌ์ง๋ฅผ R2๋ก ์ฎ๊ธด๋ค๊ณ ์์ฒญ ๋จ๊ฐ ์์ฒด๊ฐ ์ธ์ง๋ ๊ฑด ์๋์์. R2๊ฐ ์ด๊ธฐ๋ ์ง์ ์ ์ด๋๊น์ง๋ egress ํ ๊ณณ๋ฟ์
๋๋ค.
๋ฏธ๋์ด ํธ๋ํฝ์ ๋์ ํด๋ณด๋ฉด ๊ฐ์ด ์ต๋๋ค. (์๋ ์ซ์๋ ์ดํด๋ฅผ ๋๊ธฐ ์ํ ์์์ด๋ฉฐ, ์ค์ ์๋น์ค ํธ๋ํฝ ๊ธฐ์ค์ ์๋๋๋ค.)
- ํ๋ฃจ 1,000๋ง ๊ฑด ์ฝ๊ธฐ ร 30์ผ = 3์ต ๊ฑด
- (3์ต - ๋ฌด๋ฃ 1,000๋ง ๊ฑด) / 100๋ง ร $0.36 = $104.40 / ์
์ด๊ฑด โ์บ์๊ฐ ํ๋๋ ์ ๋จน์์ ๋โ์ ์ซ์์ ๋๋ค. egress๋ฅผ 0์์ผ๋ก ๋ง๋ค์ด๋๊ณ ๋ ์บ์๋ก R2 ๋๋ฌ์ ๋ง์ง ๋ชปํ๋ฉด, S3์์ ๋ด๋ ๊ฒ๊ณผ ๋ณ๋ก ๋ค๋ฅด์ง ์์ operation ๋น์ฉ์ด ๊ทธ๋๋ก ์์ด ๋๊ฐ๋๋ค. ๊ทธ๋ฌ๋ฉด ๊ตณ์ด ๋ง์ด๊ทธ๋ ์ด์ ์ ๊ฐํํ ์ด์ ๊ฐ ์์ ๋งํผ ๋น์ฉ ๊ฐ์ ํญ์ด ์์์ง๋๋ค. ์ ํ์ ์ง์ง ์ด๋์ โegress 0์โ์ด ์๋๋ผ โR2 ์ ๊ทผ์ ์บ์๋ก ์ผ๋ง๋ ํ์ด๋ง๋๋โ ์ ๋ฌ๋ ค ์์๋ ๊ฒ๋๋ค.
์ด ๊นจ๋ฌ์์ด ์ดํ ๋ชจ๋ ์ค๊ณ์ ๊ธฐ์ค์ด ๋์ต๋๋ค. ๋ชจ๋ ์์ฒญ์ R2์ ๋๋ฌํ์ง ์๋ ๊ฑธ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ผ๋๋ค. HEAD ์์ฒญ ํ๋๊น์ง๋์.
์ฝ์ง 3 โ private์ผ๋ก ์๋ตํด์ผ ํ๋๋ฐ ์บ์๋ public๋ง ์ ์ฅํ๋ค
์ฌ๊ธฐ๊ฐ ์ด๋ฒ ์ ํ์์ ๊ฐ์ฅ ์ค๋ ๋ถ์ก๊ณ ์์๋ ์ง์ ์ ๋๋ค. ๋ ์๊ตฌ์ฌํญ์ด ์ ๋ฉด์ผ๋ก ์ถฉ๋ํ์ต๋๋ค.
์๊ตฌ์ฌํญ A. ํด๋ผ์ด์ธํธ์๋ private์ผ๋ก ์๋ตํด์ผ ํ๋ค.
์ ํฌ ๋ฏธ๋์ด๋ ์ฌ์ฉ์๋ณ ๊ถํ์ด ๋ค๋ฅธ ์ฝํ
์ธ ์
๋๋ค. ๋ง์ฝ Cache-Control: public์ผ๋ก ๋ด๋ ค๋ณด๋ด๋ฉด, ์ค๊ฐ์ ๋ค์ด์คํธ๋ฆผ ํ๋ก์๋ Next.js ์๋ฒ ๊ฐ์ ๊ณต์ ์บ์๊ฐ A ์ฌ์ฉ์์ ์๋ต์ B ์ฌ์ฉ์์๊ฒ ์ฌ์ฌ์ฉํด๋ฒ๋ฆด ์ํ์ด ์์ต๋๋ค. ๊ทธ๋์ ํด๋ผ์ด์ธํธ ๊ณ์ฝ์ ๋ฌด์กฐ๊ฑด private์ด์ด์ผ ํ์ต๋๋ค.
์๊ตฌ์ฌํญ B. ์บ์์ ์ ์ฅํ๋ ค๋ฉด public์ด์ด์ผ ํ๋ค.
๋ฌธ์ ๋ ์ฌ๊ธฐ์ ๋๋ฌ๋ฌ์ต๋๋ค. ์๊ตฌ์ฌํญ A๋ฅผ ์งํค๋ ค๊ณ private์ผ๋ก ์๋ตํ๊ฒ ํ๋๋, ์๊ฐ์ด ์ง๋๋ ์บ์๊ฐ ๊ณ์ MISS๋ก๋ง ์กํ์ต๋๋ค. ์๊ณ ๋ณด๋ caches.default๋ Cache-Control: private ์๋ต์ cache.put() ํด๋ ์๋ฌ๋ ๋ก๊ทธ๋ ์์ด ์กฐ์ฉํ ์ ์ฅ์ ๊ฑด๋๋ฐ์์ต๋๋ค. ์ด ์ฌ์ค์ ๋ชจ๋ฅธ ์ฑ ํ์ฐธ์ ๋ถ๋ค๊ณ ์์์ต๋๋ค.
์บ์๊ฐ MISS๋ก๋ง ์กํ๋ค๋ ๊ฑธ ๋์ผ๋ก ํ์ธํ ์ ์์๋ ๊ฑด, Worker์์ ์๋ต์ ์บ์๋ก ๋ด์ค ๋
X-Cache: HIT, R2๊น์ง ๋ค๋ ์์ ๋X-Cache: MISS๋ฅผ ์ปค์คํ ํค๋๋ก ๋ถ์ฌ๋ ๋๋ถ์ ๋๋ค.curl -I๋ก ์ฐ์ด๋ณด๋ฉด ์๋ฌด๋ฆฌ ๋ค์ ์์ฒญํด๋ HIT์ด ๋จ์ง ์์์ต๋๋ค.
์ ๋ฆฌํ๋ฉด ์ด๋ ์ต๋๋ค.
private์ผ๋ก ์๋ตํด์ผ โ ๋ณด์ ๊ณ์ฝ ์งํด โ ํ์ง๋ง ์บ์ ์ ์ฅ ์คํจpublic์ผ๋ก ์๋ตํ๋ฉด โ ์บ์ ์ ์ฅ ์ฑ๊ณต โ ํ์ง๋ง ๋ณด์ ๊ณ์ฝ ๊นจ์ง
ํ๋์ ๋ต์ด ์์ด ๋ณด์์ต๋๋ค. ํ์๊ณผ ํ์ดํธ๋ณด๋ ์์์ ํ์ฐธ ์ด์ผ๊ธฐํ๋ค, ๋ฐ์ฏค ๋๋ด์ฒ๋ผ ๋์จ ์์ด๋์ด๊ฐ ๊ฒฐ๊ตญ ์ฑํ๋์ต๋๋ค.
โ๊ทธ๋ผโฆ ์ ์ฅํ ๋๋ public์ผ๋ก ์์ฌ์ ๋ฃ๊ณ , ๊บผ๋ด์ ์๋ตํ ๋ ๋ค์ private์ผ๋ก ๋๋๋ฆฌ๋ฉด ๋๋ ๊ฑฐ ์๋?โ
์ฒ์์ ์ด๊ฑธ ์ ๋๋ก ๋ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํ์ง ์์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ์ด๊ฒ ๋ง๊ณ ๋ ๋ ์๊ตฌ์ฌํญ์ ๋์์ ๋ง์กฑ์ํฌ ๊ธธ์ด ์์์ต๋๋ค. ํต์ฌ์ ์๋ณธ Cache-Control์ ๋ณ๋ ํค๋์ ๋ฐฑ์ ํด๋๊ณ , ์บ์์๋ public์ผ๋ก ์ ์ฅํ ๋ค, HIT๋์ด ๊บผ๋ผ ๋ ๋ฐฑ์ ํด๋ ๊ฐ์ผ๋ก ๋ณต์ํ๋ ๊ฒ๋๋ค.

// ์ ์ฅ์ฉ: ์๋ณธ CC๋ฅผ X-Original-Cache-Control ์ ๋ณด์กดํ๊ณ , ์ ์ฅ๋ณธ์ public ์ผ๋ก ์ฐํ
function buildCacheEntry(response: Response, isSigned: boolean): Response {
const cloned = response.clone();
const toCache = new Response(cloned.body, {
status: cloned.status,
headers: new Headers(cloned.headers)
});
if (isSigned) {
toCache.headers.set('X-Original-Cache-Control', toCache.headers.get('Cache-Control') ?? '');
toCache.headers.set('Cache-Control', 'public, max-age=86400');
}
return toCache;
}
// ์๋ต์ฉ: HIT ์ ์๋ณธ CC ๋ฅผ ๊ทธ๋๋ก ๋ณต์ โ ํด๋ผ์ด์ธํธ๋ ์ฌ์ ํ private ์ ์์
function restoreFromCacheEntry(cached: Response): Response {
const response = new Response(cached.body, {
status: cached.status,
headers: new Headers(cached.headers)
});
if (response.headers.has('X-Original-Cache-Control')) {
response.headers.set('Cache-Control', response.headers.get('X-Original-Cache-Control') ?? '');
response.headers.delete('X-Original-Cache-Control');
}
return response;
}
์ด๋ ๊ฒ ํ๋ ๊ณ์ธต๋ง๋ค ๋ณด๋ ๊ฐ์ด ์ ํํ ๊ฐ๋ฆฝ๋๋ค.
| ๊ณ์ธต | ๋ณด์ด๋ Cache-Control | ์๋ |
|---|---|---|
| ํด๋ผ์ด์ธํธ/๋ธ๋ผ์ฐ์ | private, max-age=86400 | ๋ธ๋ผ์ฐ์ ๋ก์ปฌ ์บ์๋ ํ์ฉ, ๊ณต์ ์บ์ ์ฌ์ฌ์ฉ์ ์ฐจ๋จ |
| ์ค๊ฐ ํ๋ก์/CDN | private | ์ฌ์ฉ์ ๊ฐ ์๋ต ์ฌ์ฌ์ฉ ๋ฐฉ์ง |
| Worker Cache API | public, max-age=86400 | cache.put() ์ ์ฅ ํ์ฑํ |
| Worker ์ธ์ฆ | ๋งค ์์ฒญ ์ํ | signed cookie/query ๊ฒ์ฆ ๋ณด์ฅ |
caches.default๋ผ๋ ๋ด๋ถ ์ ์ฅ์์๋ง ์ ๊น public์ด๋ผ๋ ๊ฐ๋ฉด์ ์์ฐ๊ณ , ๋ฐ์ผ๋ก ๋๊ฐ๋ ์๊ฐ ๋ค์ private ์ผ๊ตด๋ก ๋๋ ค๋๋ ์
์
๋๋ค. private ๊ฒฝ๋ก(signed)๋ Edge ์๋ ์บ์๋ฅผ ํ์ง ์์ผ๋ Worker๊ฐ ๋งค ์์ฒญ ์คํ๋์ด ์ธ์ฆ์ ํญ์ ๋ณด์ฅ๋๊ณ , ๊ทธ๋ฌ๋ฉด์๋ Worker Cache๋ก R2 ์ ๊ทผ์ ์ค์ด๋ญ๋๋ค.
Worker ํ๋์ ๋๋ฌ ๋ด์ ์์ํ ์ฒ๋ฆฌ๋ค
์บ์ ๋๋ ๋ง๋ฅผ ํ๊ณ ๋์๋, โCloudFront๊ฐ ์๋ฌด ๋ง ์์ด ํด์ฃผ๋ ๊ฒ๋คโ์ ํ๋ํ๋ ์์ผ๋ก ๋์ด๋ ค์ผ ํ์ต๋๋ค. ์ฝ์ง 2์์ ์ ํ ๊ธฐ์ค โ ๊ธฐ๋ณธ๊ฐ์ R2์ ๋๋ฌํ์ง ์๋ ๊ฒ โ ์ ์งํค๊ธฐ ์ํ ๋ํ ์ผ๋ค์ ๋๋ค.
Signed URL ์บ์ ํค ์ ๊ทํ.
Signed URL์ ์ฌ์ฉ์๋ง๋ค ?Policy=...&Signature=... query๊ฐ ๋ค๋ฆ
๋๋ค. ์ด๊ฑธ ๊ทธ๋๋ก ์บ์ ํค๋ก ์ฐ๋ฉด ๊ฐ์ ํ์ผ์ธ๋ฐ๋ ์ฌ์ฉ์๋ง๋ค ์บ์๊ฐ ๋ฐ๋ก ์กํ์ ํํธ์จ์ด ๋ฐ๋ฅ์ ์นฉ๋๋ค. ์บ์ ํค์์๋ query๋ฅผ ๋ฒ๋ฆฌ๊ณ pathname๋ง ์ด ์ด์ ์
๋๋ค.
// signed URL ์ ํ ํฐ query ์ ๊ฑฐ โ ๋์ผ ํ์ผ์ด ๊ฐ์ ์บ์ ์ํธ๋ฆฌ๋ฅผ ๊ณต์
function signedRequestToCacheKey(request: Request): Request {
const url = new URL(request.url);
return new Request(`${url.origin}${url.pathname}`);
}
HEAD ์์ฒญ๋ GET ์บ์๋ก ๋์ด๋ค. HEAD ์์ฒญ ์ญ์ R2 ์ ์ฅ์์ Class B operation, ๊ณง ๋์ ๋๋ค. ๊ทธ๋ฐ๋ฐ HEAD๊ฐ ํ์๋ก ํ๋ ๊ฑด ETagยทLast-ModifiedยทContent-TypeยทContent-Length ๊ฐ์ ๋ฉํ๋ฐ์ดํฐ๋ฟ์ด๊ณ , ์ด๊ฑด ์ด๋ฏธ ์ ์ฅํด๋ GET ์บ์ ์์ ๋ค ์์ต๋๋ค. HEAD๊ฐ ์ค๋ฉด GET ์บ์๋ฅผ ํค๋ ์์ค๋ก ์ฌ์ฌ์ฉํด R2๊น์ง ์ ๊ฐ๋๋ค (Cache API๋ GET๋ง ๋งค์นญํ๋ฏ๋ก ์กฐํ ์ ํค๋ GET์ผ๋ก ๋ง๋ค์ด ๋๊น๋๋ค).
์กฐ๊ฑด๋ถ ์์ฒญ 304๋ฅผ Worker์์ ๋๋ธ๋ค.
If-None-Match / If-Modified-Since๊ฐ ๋ถ์ ์์ฒญ์ด ์ค๋ฉด, ์บ์๋ ์๋ต์ ETagยทLast-Modified๋ง์ผ๋ก Worker๊ฐ ์ง์ 304๋ฅผ ๋ง๋ค์ด ๋๋ ค์ค๋๋ค. ๋ณ๊ฒฝ์ด ์๋ค๋ ๊ฑธ ํ์ธํ๋ ค๊ณ R2๊น์ง ๋ค๋
์ฌ ํ์๊ฐ ์์ต๋๋ค.
Range ์์ฒญ์ ์ ์งํ๊ฒ ์ฐํํ๋ค.
๋์์ seek์ฒ๋ผ Range(206 Partial Content) ์์ฒญ์ Cache API๊ฐ 206์ ์ ์ฅํ์ง ๋ชปํฉ๋๋ค. ์ด๊ฑด ์ต์ง๋ก ์บ์ฑํ๋ ค ํ์ง ์๊ณ R2๋ก ์ง์ ์๋นํ๋, ์๋ต์ X-Cache: BYPASS๋ฅผ ๋ฐ์ โ์๋ ์๋์ ์ผ๋ก ์บ์๋ฅผ ์ฐํํ๋คโ๋ฅผ ๋ช
์ํ์ต๋๋ค.
๊ทธ๋์ ๋๋ฒ๊น
์ฉ์ผ๋ก ๋ชจ๋ ์๋ต์ X-Cache ํค๋๋ฅผ ๋จ๊ฒผ์ต๋๋ค.
HITโ Worker Cache์์ ์ฐพ์ (R2 ์ ๊ฐ)MISSโ R2์์ ์ฝ์ด์ด (๊ทธ๋ฆฌ๊ณ ์บ์์ ์ ์ฅ)BYPASSโ Range ๋ฑ์ผ๋ก ์๋์ ์ฐํ
์ด์์์ ์บ์๊ฐ ๋๋์ง ์๋์ง๋ฅผ curl -I๋ก ํ ๋ฒ์ ํ์ธํ ์ ์์ด์, ์ด ํค๋ ํ๋๊ฐ ๋๊ณ ๋๊ณ ๋ฐฅ๊ฐ์ ํ์ต๋๋ค.
CORS ์ค์ผ ๋ฐฉ์ง.
CORS ์๋ต์ ์์ฒญ Origin์ ๋ฐ๋ผ Access-Control-Allow-Origin ๊ฐ์ด ๋ฌ๋ผ์ง๋๋ค. ์ด๊ฑธ ์บ์๊ฐ ๋ฌด์ฌ์ฝ ์ฌ์ฌ์ฉํ๋ฉด A ๋๋ฉ์ธ์ฉ ACAO๊ฐ B ๋๋ฉ์ธ์ ์๋ต๋์ด CORS ์๋ฌ๊ฐ ํฐ์ง๋๋ค. ๊ทธ๋์ Vary: Origin์ ๋ถ์ฌ โ์ด ์๋ต์ Origin๋ง๋ค ๋ค๋ฅผ ์ ์๋คโ๋ฅผ ๋ช
์ํ์ต๋๋ค.
CloudFront ํฌ๋งท ๊ทธ๋๋ก ๊ฒ์ฆํ๊ธฐ
์ฐฌํฌ๋ PoC์์๋ ์ ๊ทผ ์ ์ด๋ฅผ โWorker์์ JWT ๊ฐ์ ๊ฑธ ์๋ก ์ค๊ณํ ์ ์๋คโ๋ ๊ฐ๋ฅ์ฑ์ผ๋ก ์ด์ด๋์ต๋๋ค. ์์ ๋๋ ๋์ง๋ง, ์ค์ ์์ ๊ทธ ๊ธธ๋ก ๊ฐ๋ฉด ํด๋ผ์ด์ธํธ(์ฑ/์น)๋ฅผ ์ ๋ถ ์ ํ ํฐ ๋ฐฉ์์ผ๋ก ์ฌ๋ฐฐํฌํด์ผ ํฉ๋๋ค. ์ด๋ฏธ ๋ง์ ์ฑ๋ค์ด CloudFront Signed Cookie/URL์ ์ฐ๊ณ ์๋ ์ํฉ์์, ๊ทธ๊ฑด ์ ํ์ ๋ฆฌ์คํฌ๋ฅผ ํค์ฐ๋ ์ ํ์ด์์ต๋๋ค.
๊ทธ๋์ ์ ๋ฐ๋๋ก ๊ฐ์ต๋๋ค. ํด๋ผ์ด์ธํธ๋ ์๋ฌด๊ฒ๋ ๋ฐ๊พธ์ง ์๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ง๊ธ ๋ณด๋ด๋ CloudFront Signed Cookie/URL์, Worker๊ฐ CloudFront์ธ ์ฒ ๊ทธ๋๋ก ๊ฒ์ฆํ๊ฒ ๋ง๋ค์์ต๋๋ค.
๋ฌธ์ ๋ CloudFront์ ์๋ช ์ด ํ์ค JWT๊ฐ ์๋๋ผ๋ ์ ์ด์์ต๋๋ค. ์๋ช ์๊ณ ๋ฆฌ์ฆ๋, base64 ์ธ์ฝ๋ฉ ๋ฐฉ์๋ CloudFront ๊ณ ์ ๊ท๊ฒฉ์ด๋ผ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก๋ ๊ฒ์ฆ์ด ๋์ง ์์์ต๋๋ค. ์ด ๋ถ๋ถ์ AI์ ๋์์ ๋ฐ์ CloudFront ํฌ๋งท์ ๊ทธ๋๋ก ๊ฒ์ฆํ๋ ์ธ์ฆ ๋ก์ง์ ์ค๊ณํ๊ณ ๊ตฌํํ์ต๋๋ค. ๋๋ถ์ ์น์์ ์ค๋ Signed Cookie๋, ์๋๋ก์ด๋ ์ธ๋ถ ํ๋ ์ด์ด์ฒ๋ผ ์ฟ ํค ์ ๋ฌ์ด ๊น๋ค๋ก์ด ํ๊ฒฝ์์ ์ค๋ Signed URL๋ Worker๊ฐ ๊ทธ๋๋ก ๋ฐ์ ๊ฒ์ฆํ ์ ์๊ฒ ๋์ต๋๋ค.
๋ง์น๋ฉฐ
์ด๋ฒ ์ ํ์์ ๋ชธ์ผ๋ก ๋ฐฐ์ด ๊ฑด ๋ช ๊ฐ์ง์์ต๋๋ค. egress๊ฐ 0์์ด๋ผ๋ ๊ฒ๋ง ๋ณด๊ณ ๋ค์ด๊ฐ์ง๋ง, ์ค์ ๋ก๋ R2 ์ ๊ทผ์ ์บ์๋ก ์ผ๋ง๋ ์ค์ด๋๋๊ฐ ๊ด๊ฑด์ด์์ต๋๋ค. CloudFront์์ ๋๋ ๊ฒ Cloudflare์์ ๊ทธ๋๋ก ๋์ง ์์, ๋ฌธ์๋ณด๋ค ์ง์ ์ฐ์ด๋ณธ ๊ฐ์ ๋ฏฟ์ด์ผ ํ๋ ๊ฒ๋ ์ปธ๊ณ ์.
buildCacheEntry / restoreFromCacheEntry ๊ฐ์ ์ฝ๋๋ ์ฒ์ ๋ณด๋ฉด โ์ Cache-Control์ ๋ ๋ฒ ๋ฐ๊พธ์ง?โ ์ถ์ต๋๋ค. ์ด๊ฑด ์ค์๋ก ์๊ธด ๊ฒ ์๋๋ผ, caches.default๊ฐ private์ ๊ฑฐ๋ถํ๋ค๋ ์ ์ฝ๊ณผ ํด๋ผ์ด์ธํธ์ private์ ๋ณด์ฅํด์ผ ํ๋ค๋ ์๊ตฌ๊ฐ ๋ง๋๋ ์ง์ ์ ์ผ๋ถ๋ฌ ๊ทธ์ด๋ ๊ฒฝ๊ณ์
๋๋ค. ๊ทธ๋์ ์ฃผ์์ ์ ๋ํ ๊ธธ๊ฒ ๋ฌ์๋์ต๋๋ค. ๋ค์ ์ฌ๋์ด โ์ด๊ฑฐ ์ ์ด๋ ๊ฒ ์งฐ์ง?โ ํ ๋ ์ฝ๋๊ฐ ์ค์ค๋ก ๋๋ตํ ์ ์๋๋ก์.
์ฐฌํฌ๋ PoC๊ฐ โ์ฎ๊ธธ ์ ์๋คโ์ ์ง๋๋ฅผ ๊ทธ๋ ค์คฌ๋ค๋ฉด, ์ด ๊ธ์ ๊ทธ ์ง๋๋ฅผ ๋ค๊ณ ์ค์ ๋ก ๊ฑธ์ด๋ณด๋ฉฐ ๋ง๋ ์ ๋ฉ์ด๋ค์ ๊ธฐ๋ก์ ๋๋ค. 4KยทAES-128์ MediaConvert์ ๋จ๊ธด ํ์ด๋ธ๋ฆฌ๋ ๊ฒฐ๋ก ์ ๊ทธ๋๋ก ์ ์ง๋๊ณ ์๊ณ , ์ด๋ฏธ์งยท์ผ๋ฐ VOD ๋ผ์ธ์ ์ด์ Cloudflare ์์์ ๋์๊ฐ๊ณ ์์ต๋๋ค.
๊ธด ๊ธ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.