הגדרת Varnish Cache להאצת HTTP

כשהאתר שלכם מגיב לאט מדי, גולשים עוזבים למתחרים ועומס השרת גדל. אנחנו מגדירים Varnish Cache להאצת HTTP כדי לזרז אספקת עמודים ולהפחית עומס על השרת. הצוות שלנו מספק את הפרויקט במפתח מלא—מניתוח ארכיטקטורה ועד יישום ותמיכה שוטפת, תוך הבטחת ביצועים יציבים גם בעומסי שיא.

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

הגדרת Varnish Cache להאצת HTTP

שימו לב: כאשר השרת האחורי מגיב תוך 300-500 אלפיות השנייה אך המשתמש מצפה לדף תוך 50 אלפיות השנייה, מטמון nginx רגיל אינו מספק את ההאצה הנדרשת. Varnish Cache פותר זאת ברמת הליבה: הוא מאחסן תגובות בזיכרון RAM ומעבד עשרות אלפי בקשות בשנייה על חומרה סטנדרטית. לדוגמה, בעומס של 10,000 בקשות בשנייה, Varnish יכול לספק תגובות שמורות במטמון תוך 1-2 אלפיות השנייה, בעוד nginx עם מטמון לוקח 5-10 אלפיות השנייה.

אנו מגדירים Varnish מקצה לקצה עבור פרויקטים עם כל ארכיטקטורה — מאתרי מדיה ועד API בעומס גבוה. בניסיון שלנו, ישנם מקרים עם שיעורי פגיעה מעל 95% והפחתת עומס על השרת האחורי ב-80%. פרויקט אחד — חנות מסחר אלקטרוני עם 500,000 מוצרים — לאחר הטמעת Varnish, זמן טעינת דף המוצר ירד משנייה אחת ל-30 אלפיות השנייה, ועלויות משאבי הענן החודשיות ירדו מ-$3000 ל-$500.

הלקוחות מקבלים לא רק את התצורה אלא גם תיעוד תפעולי והדרכה לצוות. במאמר זה נסקור בעיות טיפוסיות: אחסון עוגיות לא תקין, התעלמות ממצב grace, וחוסר ב-Purge API.

ארכיטקטורה: Varnish מול nginx

Клиент → Varnish :80 → nginx :8080 → Backend :3000 

Varnish אינו יכול לטפל ב-SSL, ולכן בסביבת ייצור, nginx או HAProxy ממוקמים לפניו לצורך סיום HTTPS:

Клиент → nginx :443 (SSL termination) → Varnish :80 → nginx :8080 → Backend 

או השתמשו בhitch — פרוקסי TLS המיועד במיוחד לשילוב עם Varnish.

למה Varnish במקום מטמון nginx?

nginx הוא שרת אינטרנט ופרוקסי הפוך מצוין, אך מערכת המטמון שלו מוגבלת. Varnish מיועד אך ורק למטמון: שפת VCL גמישה, שליטה מדויקת ב-TTL, מצבי grace ו-stale, מנגנון ban מובנה, וסטטיסטיקות מפורטות. בפרויקטים עם שיעורי פגיעה מתחת ל-90% וגודל מטמון מעל 1 GB, Varnish מספק יתרון מהירות של פי 2-5 על פני nginx.

תכונה Varnish מטמון nginx
גמישות בתצורה VCL — שליטה מלאה הנחיות מוגבלות
שיעור פגיעה 85-98% 70-80% אופייני
Grace/Stale כן לא
מנגנון Ban מובנה לא

VCL: שפת התצורה

VCL (Varnish Configuration Language) היא שפה דמוית C, המהודרת לקוד מקורי בעת הטעינה. זה מספק מהירות אך דורש הבנה של מכונת המצבים של Varnish: Клиент → Varnish :80 → nginx :8080 → Backend :3000 → Клиент → nginx :443 (SSL termination) → Varnish :80 → nginx :8080 → Backend → vcl_recv/vcl_hash → vcl_hit → vcl_miss.

תצורה בסיסית /etc/varnish/default.vcl

vcl 4.1;
import std;

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 60s;
    .between_bytes_timeout = 30s;
}

sub vcl_recv {
    # Убираем порт из Host для правильного кэш-ключа
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # Не кэшируем POST, PUT, DELETE
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # Не кэшируем авторизованные запросы
    if (req.http.Authorization || req.http.Cookie ~ "session") {
        return (pass);
    }

    # Убираем маркетинговые параметры из URL для лучшего hit rate
    set req.url = regsuball(req.url, "([?&])(utm_[a-z]+|fbclid|gclid)=[^&]+", "\1");
    set req.url = regsub(req.url, "[?&]$", "");

    return (hash);
}

sub vcl_hash {
    hash_data(req.url);
    hash_data(req.http.Host);

    # Разделяем кэш для mobile/desktop если нужно
    if (req.http.X-Device-Type) {
        hash_data(req.http.X-Device-Type);
    }

    return (lookup);
}

sub vcl_backend_response {
    # Кэшируем 404 на 1 минуту чтобы не долбиться в бэкенд
    if (beresp.status == 404) {
        set beresp.ttl = 1m;
        set beresp.grace = 30s;
    }

    # Grace period: отдаём устаревший кэш пока обновляется
    set beresp.grace = 30s;

    # Не кэшируем если бэкенд сказал no-cache
    if (beresp.http.Cache-Control ~ "no-cache|no-store|private") {
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
    }

    # По умолчанию кэшируем 10 минут
    if (!beresp.http.Cache-Control) {
        set beresp.ttl = 10m;
    }

    return (deliver);
}

sub vcl_deliver {
    # Добавляем заголовок для дебага
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache = "MISS";
    }

    # Убираем внутренние заголовки Varnish
    unset resp.http.X-Varnish;
    unset resp.http.Via;

    return (deliver);
}
דוגמת תצורה עבור WordPress (אקורדיון)

עבור WordPress, לעיתים קרובות יש צורך להחריג בקשות admin ו-ajax. הוסיפו ל-vcl_fetch:

if (req.url ~ "wp-admin|wp-login|ajax") { return (pass); } 

מקרה בוחן: חנות מסחר אלקטרוני עם 500,000 מוצרים

הלקוח התלונן על טעינה איטית של דפי מוצר (מעל שנייה אחת). הסיבה הייתה שמטמון nginx לא אחסן תגובות בגלל עוגיות סשן. הטמענו Varnish עם כלל להתעלם מעוגיות סשן עבור משתמשים אורחים והגדרנו תקופת grace של 30 שניות. שיעור הפגיעה עלה מ-45% ל-93%, וזמן התגובה ירד ל-30 אלפיות השנייה.

איך להגדיר Varnish לשיעור פגיעה מקסימלי?

כדי להשיג שיעור פגיעה של 90%+, פעלו לפי הכללים הבאים:

  • נקו את ה-URL מפרמטרים שיווקיים (utm, fbclid).
  • התעלמו מעוגיות סשן עבור משתמשים לא מאומתים.
  • השתמשו ב-TTL מפורט: שעות לסטטי, דקות לתוכן.
  • הפעילו מצב grace כך שהשרת האחורי לא יחסום את התגובה במהלך רענון.

איך להגדיר Varnish: מדריך שלב אחר שלב

  1. התקינו Varnish מהמאגר (varnish-cache.org).
  2. הגדירו את השרת האחורי ב-default.vcl (host ו-port של שרת האינטרנט שלכם).
  3. הגדירו כללי vcl_recv: החריגו POST, בקשות מאומתות, וכתובות admin.
  4. הגדירו vcl_backend_response: TTL, grace, טיפול ב-no-cache.
  5. הוסיפו תמיכה ב-PURGE: ACL וכלל ב-vcl_recv.
  6. הפעילו ניטור: varnishstat ושילוב עם Prometheus.

Purge: ביטול מטמון מאולץ

acl purge_acl {
    "localhost";
    "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);
    }
}

בטלו URL ספציפי: vcl_deliver. לביטול המוני לפי תבנית, השתמשו ב-vcl 4.1; import std; backend default { .host = "127.0.0.1"; .port = "8080"; .connect_timeout = 5s; .first_byte_timeout = 60s; .between_bytes_timeout = 30s; } sub vcl_recv { # Убираем порт из Host для правильного кэш-ключа set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); # Не кэшируем POST, PUT, DELETE if (req.method != "GET" && req.method != "HEAD") { return (pass); } # Не кэшируем авторизованные запросы if (req.http.Authorization || req.http.Cookie ~ "session") { return (pass); } # Убираем маркетинговые параметры из URL для лучшего hit rate set req.url = regsuball(req.url, "([?&])(utm_[a-z]+|fbclid|gclid)=[^&]+", "\1"); set req.url = regsub(req.url, "[?&]$", ""); return (hash); } sub vcl_hash { hash_data(req.url); hash_data(req.http.Host); # Разделяем кэш для mobile/desktop если нужно if (req.http.X-Device-Type) { hash_data(req.http.X-Device-Type); } return (lookup); } sub vcl_backend_response { # Кэшируем 404 на 1 минуту чтобы не долбиться в бэкенд if (beresp.status == 404) { set beresp.ttl = 1m; set beresp.grace = 30s; } # Grace period: отдаём устаревший кэш пока обновляется set beresp.grace = 30s; # Не кэшируем если бэкенд сказал no-cache if (beresp.http.Cache-Control ~ "no-cache|no-store|private") { set beresp.uncacheable = true; set beresp.ttl = 120s; return (deliver); } # По умолчанию кэшируем 10 минут if (!beresp.http.Cache-Control) { set beresp.ttl = 10m; } return (deliver); } sub vcl_deliver { # Добавляем заголовок для дебага if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; set resp.http.X-Cache-Hits = obj.hits; } else { set resp.http.X-Cache = "MISS"; } # Убираем внутренние заголовки Varnish unset resp.http.X-Varnish; unset resp.http.Via; return (deliver); } .

ניטור

# Статистика в реальном времени
varnishstat
# Просмотр логов запросов
varnishlog -i ReqURL,RespStatus,ObjTTL
# Hit rate за последние 10 секунд
varnishstat -f MAIN.cache_hit,MAIN.cache_miss -1

שיעור פגיעת המטמון היעד עבור אתרי מדיה ומסחר אלקטרוני הוא 85%+. אם הוא מתחת ל-60%, או שיש יותר מדי תוכן מותאם אישית, או שעוגיות חוסמות את המטמון באגרסיביות יתר. לאחר הטמעת Varnish, גם הפחתנו עלויות CDN: בפרויקט אחד, החיסכון הסתכם ב-$1500 חודשיים.

תהליך ולוח זמנים

שלב לוח זמנים
ביקורת ארכיטקטורה וסקירת לוגיקת המטמון יום אחד
עיצוב וכתיבת VCL 2-3 ימים
שילוב עם SSL (nginx/hitch) יום אחד
הגדרת Purge API וניטור 1-2 ימים
תיעוד והדרכה יום אחד

העלות מחושבת באופן אישי לאחר ביקורת — צרו קשר להערכת הפרויקט שלכם. קבלו ייעוץ ממהנדס על האצת יישומי אינטרנט.

מה כלול

  • תצורת VCL מותאמת לפרויקט שלכם
  • הגדרת Purge API (מנגנון ban לפי URL ותבניות)
  • שילוב SSL (nginx או hitch)
  • ניטור והתראות (Prometheus + לוח מחוונים של Grafana)
  • תיעוד תפעולי ונוהל ביטול מטמון
  • הדרכת צוות (1-2 שעות)
  • אחריות על התצורה — 30 יום לאחר ההפעלה

הניסיון והתוצאות שלנו

אנו עובדים עם Varnish למעלה מ-5 שנים, ומגדירים מטמון לפרויקטים עם עומסים של עד 50,000 בקשות בשנייה. תוצאות אופייניות: שיעור פגיעה 92-98%, הפחתת עומס על השרת האחורי ב-80%, ירידה בזמן התגובה הממוצע מ-200-400 אלפיות השנייה ל-5-20 אלפיות השנייה. כל המהנדסים מוסמכים ב-Varnish וב-Kubernetes. קראו עוד על VCL בספר Varnish Book.

טעויות נפוצות בתצורת Varnish

  • אחסון כל ה-URLs במטמון: התעלמות מ-POST, בקשות מאומתות, ופאנלי admin. נכון: רק GET/HEAD ללא סשן.
  • TTL גדול מדי: עבור אתרים דינמיים (מסחר אלקטרוני) האופטימלי הוא 1-10 דקות.
  • חוסר ב-Purge API: ללא מנגנון ban, ביטול המטמון הופך לפעולה ידנית.
  • התעלמות מ-grace: כאשר השרת האחורי נכשל, Varnish צריך לשרת מטמון מיושן (stale), אחרת ייווצרו שגיאות.

אם הפרויקט שלכם דורש האצה — צרו קשר. אנו נעריך את הארכיטקטורה ונציע פתרון.