⚡ धडा 04 — Edge वर dynamic pages: live pages सुद्धा, काही सेकंदांसाठी
📍 तुम्ही इथे आहात: 13 पैकी धडा 04 · मागे: lesson-03-cloudfront-s3 · पुढे: lesson-05-stateless-load-balancer
📦 या ब्रँचमध्ये काय आहे
धडे 01–03, आणि त्याशिवाय बदलणारी pages cache करणे: प्रत्येक response ने द्यायला हवी अशी
तीन Cache-Control उत्तरे (एक वर्ष, काही सेकंद, कधीच नाही), stale-while-revalidate,
अनेक edges नी एकदम origin ला विचारणे थांबवणारे origin shield, आणि edge
functions (CloudFront Functions आणि Lambda@Edge). scale/demo.py मधले
edge() प्रत्येक गोष्ट दाखवते.
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
वर्ग 3A ची निकालाची यादी फक्त शिक्षिकेने grade save केल्यावरच बदलते — तासाला काही वेळा. पण निकालाच्या दिवशी दर सेकंदाला हजारो पालक ती मागतात.
दीपिका फाटकावरच्या टेबलांना सांगते: "तुम्ही निकालाच्या यादीची प्रत काढू शकता, पण 10 सेकंदांनी तुमची प्रत फेकून द्या." आता प्रत्येक फाटक सेकंदाला 2,000 वेळा नव्हे, तर दर 10 सेकंदांनी एकदा office कडे धावते. पालकाला काही सेकंद जुनी यादी दिसू शकते. निकालाच्या दिवशी त्याची कुणालाच हरकत नसते.
फाटके अनेक आहेत. प्रत्येक फाटक स्वतःच office कडे धावले, तर office मध्ये तरीही धावणाऱ्यांची गर्दी होते. म्हणून दीपिका office शेजारी एक मोठे प्रतींचे टेबल ठेवते — origin shield. फाटके त्या टेबलाला विचारतात; फक्त ते टेबल office ला विचारते.
काही कागद खाजगी असतात: कतरिनाचे स्वतःचे प्रगतिपुस्तक. फाटकांनी त्यांची प्रत कधीच काढायची नाही. प्रत्येक कागदावर तो कोणत्या प्रकारचा आहे हे सांगणारे लेबल असते: "एक वर्षासाठी प्रत काढा", "10 सेकंदांसाठी प्रत काढा", किंवा "कधीच प्रत काढू नका".
🗺️ आकृती
flowchart LR
e1["📄 edge 1"] --> sh["🛡️ origin shield<br/>one regional cache"]
e2["📄 edge 2"] --> sh
e3["📄 edges 3–5"] --> sh
sh -->|"6 requests a minute"| api["🍳 origin: results API"]
subgraph labels["🏷️ Cache-Control on each answer"]
a["/app.3f9c.js<br/>public, max-age=31536000, immutable"]
b["/results/3A<br/>public, s-maxage=10, stale-while-revalidate=30"]
c["/me<br/>private, no-store"]
end
🗺️ काढलेली आकृती + एक lab: https://school-edh.pages.dev/scaling/lesson-diagrams.html#l04
❓ काय
Cache-Control— origin ज्या header मधून caches ना काय करायचे ते सांगतो:public, max-age=31536000, immutable— versioned file: एक वर्ष ठेवा (browsers आणि CDNs);public, s-maxage=10— shared caches (CloudFront) ते 10 सेकंद ठेवू शकतात; shared caches साठीs-maxageहेmax-ageवर मात करते;private, no-store— वैयक्तिक data: कोणताही shared cache ते ठेवू शकत नाही, आणि browser ने सुद्धा ते साठवू नये.
- Micro-caching — गर्दीचे, dynamic, public page काही सेकंदांसाठी cache करणे. 2,000 req/s ला, 10 सेकंदांचा cache प्रत्येक location मागच्या 20,000 origin requests ची एक करतो.
- stale-while-revalidate=30 — प्रत expire झाल्यानंतर 30 सेकंद cache जुन्या प्रतीने उत्तर देऊ शकतो,
त्याच वेळी background मध्ये नवी प्रत आणत असताना. भेट देणाऱ्यांना refresh साठी कधीच
थांबावे लागत नाही. CloudFront
stale-while-revalidate(आणिstale-if-error) support करतो. - Origin shield — तुमच्या origin समोर, एका Region मधला caching चा एक जादा थर. प्रत्येक edge आणि regional cache shield ला विचारतो; फक्त shield origin ला विचारतो. त्याचा प्रत्येक request ला जादा खर्च येतो, आणि अनेक locations ना एकाच क्षणी miss होत असेल तेव्हा तो फायद्याचा ठरतो.
- Cache policy विरुद्ध origin request policy — cache policy cache key आणि TTL limits ठरवते; origin request policy कोणते जादा headers, cookies आणि query strings cache न विभागता origin कडे पुढे पाठवायचे ते ठरवते.
- Edge functions — edge वरचा लहान code:
- CloudFront Functions — JavaScript, फक्त viewer request / viewer response, खूप लहान runs, network calls नाहीत. Redirects, URL rewrites, header बदल, साध्या token checks साठी.
- Lambda@Edge — Node.js किंवा Python, चारही events (viewer आणि origin, request आणि response), network calls चालतात, जास्त लांब runs. Auth service ला call करण्यासारख्या जड कामांसाठी.
🤔 का
कारण निकालाच्या दिवशी सर्वात गर्दीचे page dynamic असते — निकाल. ते एक वर्षासाठी
cache करता येत नाही, पण 10 सेकंदांसाठी करता येते, आणि त्याचा जवळपास सगळा load काढून टाकायला
10 सेकंद पुरेसे आहेत. मग origin shield "प्रत्येक edge एकदम विचारतो" ही गर्दी काढून टाकतो.
आणि private, no-store लेबलच एका पालकाला दुसऱ्या मुलाचे प्रगतिपुस्तक पाहण्यापासून
रोखते.
🔧 कसे (या repo मध्ये)
edge() तीन Cache-Control उत्तरे print करते, मग 5 EdgeCache(10) edges बनवते
आणि 60 सेकंद प्रत्येकाला सेकंदाला एक request पाठवते. Shield नसताना, प्रत्येक edge miss
origin कडे जातो. Shield असताना, edge miss आधी shield ला (आणखी एक EdgeCache(10)) विचारतो,
आणि फक्त shield miss च origin पर्यंत पोहोचतो. Edge functions चे वर्णन केले आहे, ती चालवली जात नाहीत.
🧪 करून पाहा
python3 scale/demo.py edge
python3 - <<'EOF'
import sys; sys.path.insert(0, "scale"); from sim import EdgeCache
def run(n_edges, ttl, shield_on):
edges, shield, origin = [EdgeCache(ttl) for _ in range(n_edges)], EdgeCache(ttl), 0
for t in range(60):
for e in edges:
if e.get("/results/3A", t) == "MISS":
if not shield_on or shield.get("/results/3A", t) == "MISS": origin += 1
return origin
for n in (5, 20):
for ttl in (1, 10, 30):
print(f"{n:>2} edges, s-maxage {ttl:>2} s → origin {run(n, ttl, False):>4} without shield, {run(n, ttl, True):>3} with shield")
EOF
✅ तपासा — तुम्हाला काय दिसायला हवे
edge तीन headers print करते
(/app.3f9c.js Cache-Control: public, max-age=31536000, immutable,
/results/3A Cache-Control: public, s-maxage=10, stale-while-revalidate=30,
/me Cache-Control: private, no-store), मग
── 5 edge locations, s-maxage 10 s, 60 s of traffic: origin gets 30 requests; with an origin shield: 6.
तुमचा snippet हे print करतो:
5 edges, s-maxage 1 s → origin 300 without shield, 60 with shield
5 edges, s-maxage 10 s → origin 30 without shield, 6 with shield
5 edges, s-maxage 30 s → origin 10 without shield, 2 with shield
20 edges, s-maxage 1 s → origin 1200 without shield, 60 with shield
20 edges, s-maxage 10 s → origin 120 without shield, 6 with shield
20 edges, s-maxage 30 s → origin 40 without shield, 2 with shield
🏁 तुम्ही आत्ताच काय सिद्ध केले
Shield नसताना origin वरचा load edges च्या संख्येबरोबर वाढतो (5 → 20 edges:
30 → 120 requests). Shield असताना तो फक्त TTL वर अवलंबून असतो: 10 s ला मिनिटाला 6,
edges कितीही असोत. जास्त लांब s-maxage दोन्ही कमी करतो.
⚠️ नेहमीच्या चुका
- cookie set करणारा किंवा एका user चा data असलेला response public key खाली cache करणे — एका
पालकाला दुसऱ्या मुलाचे page दिसते. वैयक्तिक pages
private, no-storeपाठवतात - public page च्या cache key मध्ये
Authorizationheader किंवा session cookie टाकणे — प्रत्येक user ला स्वतःची प्रत मिळते, आणि hit ratio शून्यावर येतो - API उत्तरांवर
Cache-Controlच नसणे, म्हणजे cache policy चा default TTL तुमच्यासाठी ठरवतो - CloudFront Function मध्ये जड काम — त्याला network access नसतो; त्या कामासाठी Lambda@Edge किंवा origin लागतो
- origin पासून दूरच्या Region मध्ये origin shield चालू करणे
🏭 प्रत्यक्ष वापरात
On a real account — results API साठी एक cache policy जी origin चा
s-maxage (0 ते 60 सेकंदांमध्ये) मानते आणि key फक्त path आणि class query string वर ठेवते:
aws cloudfront create-cache-policy --cache-policy-config '{
"Name": "results-micro-cache",
"MinTTL": 0, "DefaultTTL": 5, "MaxTTL": 60,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true, "EnableAcceptEncodingBrotli": true,
"HeadersConfig": { "HeaderBehavior": "none" },
"CookiesConfig": { "CookieBehavior": "none" },
"QueryStringsConfig": { "QueryStringBehavior": "whitelist",
"QueryStrings": { "Quantity": 1, "Items": ["class"] } }
}
}'
Terraform — API origin साठी origin shield चालू करा:
origin {
domain_name = "api.school.example"
origin_id = "results-api"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
origin_shield {
enabled = true
origin_shield_region = "ap-south-1" # the Region closest to the origin
}
}
जुन्या links नव्या path कडे पाठवणारे एक CloudFront Function (viewer request):
function handler(event) {
var req = event.request;
if (req.uri.indexOf('/old-results/') === 0) {
return { statusCode: 301, statusDescription: 'Moved Permanently',
headers: { location: { value: req.uri.replace('/old-results/', '/results/') } } };
}
return req;
}
🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: launch आधी प्रत्येक route चे लेबल ठरवा — "एक वर्ष", "काही सेकंद" किंवा "कधीच नाही" — आणि "कधीच नाही" routes दोन वेगवेगळ्या users सह test करा. वैयक्तिक page वरची caching ची चूक म्हणजे हळू page नव्हे, तर data leak.
⏭️ पुढे
UI फाटकांवरून दिली जाते. तुमच्यापर्यंत पोहोचायलाच हव्यात अशा requests आता API वर येतात. एक खिडकी पुरेशी नाही — पण जास्त खिडक्या तेव्हाच चालतात जेव्हा कोणतीही खिडकी कोणत्याही पालकाला सेवा देऊ शकते.
git checkout lesson-05-stateless-load-balancer