כאשר שרת האינטרנט שלך מתחיל להיחנק תחת עומסי שיא וזמן התגובה (TTFB) עולה על 500 אלפיות השנייה, הגיע הזמן ליישם מאיץ HTTP. Varnish Cache מיירט בקשות לפני השרת האחורי ומשרת תגובות שמורות במטמון מזיכרון RAM. זה מפחית את זמן האחזור ל-1–5 אלפיות השנייה והשרת יכול לטפל בעשרות אלפי בקשות בשנייה. אנחנו צוות עם 5 שנות ניסיון מעשי, שיישמנו Varnish עבור יותר מ-100 שירותי עומס גבוה. תצורה נכונה משפרת ישירות את Core Web Vitals (LCP, INP) ויכולה לחסוך עד 500,000 רובל בשנה בתשתית שרתים. שיעור פגיעה אופייני עם VCL נכון מגיע ל-95–99%, וזמן התגובה יורד פי 100 בהשוואה לבקשות ישירות לשרת האחורי.
בעיות שאנחנו פותרים
- עומס גבוה על השרת האחורי. ללא מטמון, כל בקשה מעובדת על ידי האפליקציה — שאילתות מסד נתונים, רינדור, לוגיקה עסקית. Varnish מוריד עד 90% מהבקשות על ידי הגשת דפים שמורים במטמון ישירות.
- דפים דינמיים איטיים. גם אם דף נוצר ב-200 אלפיות השנייה, תחת 1000 בקשות במקביל זמן האחזור מזנק. Varnish עם Edge Side Includes (ESI) שומר במטמון את החלקים המשותפים בעוד בלוקים אישיים נטענים באופן אסינכרוני. זה מקצר את זמן יצירת הדף ב-60–80%.
- ביצועים לא יציבים תחת פסגות תנועה. Varnish פועל כמאגר: אם השרת האחורי מושבת זמנית, הוא מגיש עותקים מיושנים (מצב grace). זה מונע השבתות ושגיאות 503.
כיצד Varnish Cache משפר את Core Web Vitals
Core Web Vitals הם מדדים שמשפיעים על דירוג Google. Varnish משפיע ישירות על Largest Contentful Paint (LCP) ו-Interaction to Next Paint (INP). על ידי שמירת דפי HTML במטמון, LCP יורד מ-2–3 שניות ל-200–300 אלפיות השנייה. INP משתפר כי השרת מספק תוכן מהר יותר, מה שמפחית עיכובים בסקריפטים. בפלטפורמת מסחר אלקטרוני אחת, העלינו את שיעור הפגיעה מ-40% ל-98% על ידי כתיבה מחדש של ה-VCL לטיפול בבקשות AJAX והגדרת TTL מתאימים. זה הפחית את העומס על השרת האחורי ב-90% וקיצר את זמני טעינת הדפים מ-3 שניות לפחות מ-200 אלפיות השנייה.
מצב Grace: למה זה חשוב
מצב grace מאפשר ל-Varnish להגיש מטמון מיושן כאשר השרת האחורי לא מגיב בזמן. כפי שמצוין בתיעוד Varnish: מצב grace מאפשר הגשת מטמון מיושן למניעת שגיאות 503. הגדרת beresp.grace = 6h נותנת לשרת האחורי 6 שעות להתאושש בזמן ש-Varnish ממשיך לספק עותקים ישנים. זה קריטי לפרויקטים בעומס גבוה שבהם כל שנייה של השבתה עולה כסף.
מתי Varnish לא נחוץ
Varnish אינו יעיל לתוכן מותאם אישית מלא (למשל, לוחות בקרה של חשבונות, בנקאות מקוונת) שבו כל בקשה דורשת נתונים ייחודיים. במקרים כאלה, מטמון ברמת האפליקציה (Redis, Memcached) או CDN מתאים יותר. עם זאת, גם עבור פרויקטים כאלה Varnish יכול לשמור במטמון נכסים סטטיים ובלוקי דפים משותפים.
הגישה שלנו לתצורת VCL
אנחנו מתחילים עם VCL בסיסי מוצק ואז מתאימים אותו לאפליקציה שלך. להלן תצורה סטנדרטית שאנחנו משתמשים בה כנקודת התחלה.
# Debian/Ubuntu apt install varnish # /etc/varnish/default.vcl vcl 4.1;
import std;
backend default {
.host = "127.0.0.1";
.port = "8080";
.first_byte_timeout = 60s;
.connect_timeout = 5s;
.between_bytes_timeout = 10s;
}
# Несколько бэкендов с балансировкой
import directors;
backend app1 {
.host = "10.0.0.1";
.port = "8080";
}
backend app2 {
.host = "10.0.0.2";
.port = "8080";
}
sub vcl_init {
new cluster = directors.round_robin();
cluster.add_backend(app1);
cluster.add_backend(app2);
}
sub vcl_recv {
set req.backend_hint = cluster.backend();
# Нормализация URL (удалить trailing slash кроме корня)
if (req.url ~ "^(/[^?]+)/$") {
set req.url = regsub(req.url, "/$", "");
}
# Не кэшировать admin-панель
if (req.url ~ "^/admin") {
return (pass);
}
# Не кэшировать авторизованных пользователей (если контент персонализирован)
if (req.http.Authorization || req.http.Cookie ~ "session_id|auth_token") {
return (pass);
}
# Удалить маркетинговые параметры из ключа кэша
set req.url = regsuball(req.url, "(\\?|&)(utm_source|utm_medium|utm_campaign|utm_content|fbclid|gclid)=[^&]+", "");
set req.url = regsub(req.url, "\\?&", "?");
set req.url = regsub(req.url, "\\?$", "");
# Нормализовать Accept-Encoding
if (req.http.Accept-Encoding) {
if (req.url ~ "\\.(gif|jpg|jpeg|png|webp|avif|ico|zip|gz|mp4)$") {
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "br") {
set req.http.Accept-Encoding = "br";
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} else {
unset req.http.Accept-Encoding;
}
}
}
sub vcl_backend_response {
# Кэшировать 404 ненадолго
if (beresp.status == 404) {
set beresp.ttl = 30s;
return (deliver);
}
# Кэшировать только успешные ответы
if (beresp.status != 200 && beresp.status != 301 && beresp.status != 302) {
set beresp.uncacheable = true;
return (deliver);
}
# Если backend не прислал Cache-Control — установить по умолчанию
if (!beresp.http.Cache-Control) {
if (bereq.url ~ "\\.(css|js|woff2|png|jpg|svg)$") {
set beresp.ttl = 30d;
} else {
set beresp.ttl = 5m;
}
}
# Grace period: отдавать устаревший кэш при backend сбое
set beresp.grace = 6h;
# Сжатие
if (beresp.http.content-type ~ "text/(html|css|javascript|xml|plain)" || beresp.http.content-type ~ "application/(json|javascript)") {
set beresp.do_gzip = true;
}
# Не хранить Set-Cookie в кэше
unset beresp.http.Set-Cookie;
}
sub vcl_deliver {
# Debug заголовок (отключить в production)
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT " + obj.hits;
} else {
set resp.http.X-Cache = "MISS";
}
# Скрыть внутренние заголовки от клиента
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.X-Powered-By;
}
sub vcl_hit {
if (obj.ttl >= 0s) {
return (deliver);
}
# Grace: отдать устаревший объект
if (obj.ttl + obj.grace > 0s) {
return (deliver);
}
return (restart);
} ביטול מטמון: PURGE, BAN, ESI
acl purge_acl {
"127.0.0.1";
"10.0.0.0"/8;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge_acl) {
return (synth(405, "Not allowed"));
}
return (purge);
}
if (req.method == "BAN") {
if (!client.ip ~ purge_acl) {
return (synth(405, "Not allowed"));
}
ban("req.http.host == " + req.http.host + " && req.url ~ " + req.url);
return (synth(200, "Ban added"));
}
}שימוש מהאפליקציה:
# Инвалидировать конкретный URL
curl -X PURGE http://localhost/page/about
# Инвалидировать по паттерну (BAN)
curl -X BAN -H "Host: company.com" http://localhost/category/ ESI (Edge Side Includes)
sub vcl_backend_response { if (beresp.http.Surrogate-Control ~ "ESI/1.0") { set beresp.do_esi = true; } } תהליך העבודה שלנו
- ביקורת אפליקציה: ניתוח URLs, עוגיות, סשנים, תדירות עדכון.
- עיצוב VCL: הגדרת חוקי מטמון, TTL, grace, דרישות ESI.
- בדיקות בסביבת staging: מדידת שיעור פגיעה, עומס על השרת האחורי, מהירות דפים.
- פריסה: הגדרת systemd, הקצאת זיכרון, ניטור.
- ניטור ואופטימיזציה: שימוש ב-varnishstat, Prometheus, איטרציות על VCL.
רשימת בדיקה לביקורת אפליקציה לפני הגדרת Varnish
- ניתוח מבנה URLs ופרמטרים
- זיהוי דפים דינמיים לעומת סטטיים
- בדיקת שימוש בעוגיות וסשנים
- קביעת תדירות עדכון התוכן
- איתור צווארי בקבוק בביצועי השרת האחורי
לוח זמנים ומה כלול
הגדרת Varnish בסיסית עם VCL סטנדרטי אורכת 1–2 ימי עבודה. עבור פרויקטים עם ארכיטקטורה מותאמת, ESI, או חוקי ביטול מורכבים, צפו 2–3 ימים. העלות נקבעת לאחר ביקורת; חיסכון אופייני במשאבי שרת של 30–40% מפחית משמעותית את הוצאות האירוח.
מה כלול בשירות שלנו
- ביקורת הארכיטקטורה הנוכחית וזיהוי צווארי בקבוק
- תצורת VCL מותאמת אישית לאפליקציה שלך
- הגדרת איזון עומסים ומצב grace
- ביטול מטמון PURGE/BAN ויישום ESI במידת הצורך
- בדיקות בסביבת staging ומדידת ביצועים
- פריסה לייצור עם ניטור (Prometheus + Grafana)
- תיעוד והדרכת צוות
- תמיכה עם אחריות לאחר הפריסה
טעויות תצורה אופייניות
| טעות | פתרון |
|---|---|
| התעלמות מנורמליזציה של URLs | הוספת נורמליזציה של סלאש בסוף ב-vcl_recv |
| שמירת דפים מאומתים במטמון | בדיקת עוגיות ו-Header של Authorization; החזרת return(pass) לתוכן מותאם אישית |
| TTL ארוך מדי לתוכן דינמי | הגדרת TTL סביר (1–5 דקות) לדפים שמתעדכנים תדיר |
| סוג תוכן | TTL | Grace | ESI | דוגמת URL |
|---|---|---|---|---|
| סטטי (CSS, JS, תמונות) | 30 יום | 12 שעות | לא | /static/css/app.css |
| דפי קטלוג | 5 דקות | 6 שעות | כן (למסננים) | /catalog/phones/ |
| דפים מותאמים אישית | 0 (pass) | - | לא | /account/ |
ללמידה מעמיקה יותר של VCL אנו ממליצים על תיעוד Varnish. צרו קשר כדי לדון בפרויקט שלכם ולקבל ביקורת ביצועים של Varnish.







