Varnish Notları

Varnish web uygulamalarını hızlandırmaya yarayan faydalı bir araç. Web sunucusunun önünde yer alır ve içeriği cache’ler. Böylece aynı içeriği ulaşmak isteyen kullanıcılar için, uygulama, aynı output’u üretmek için tekrar tekrar uğraşmaz. Belirlenen cache süresi içinde sayfayı ziyaret eden kullanıcılar web sunucusuna uğramadan, istedikleri içeriği Varnish’den hızlıca alırlar. Cache süresi bitiminde ise kullanıcılardan bir tanesi tarafından oluşturulan içerik tekrar cache’lenir, bu sırada diğer ziyaretçiler içeriğin oluşmasını bekler, bu sayede race condition durumu engellenir.

Varnish ayarları VCL (Varnish Configuration Language) ile yapılır. Aşağıda bir isteğin hangi VCL methotlarına, hangi sırayla, hangi koşulda uğradığını gösteren bir akış şeması mevcut:

VCL

Bu da örnek bir VCL dosyası:

# 8080 portunda çalışan web sunucusunu kullansin
backend default {
  .host = "127.0.0.1";
  .port = "8080";
}

sub vcl_recv {

  # Non-RFC2616 or CONNECT which is weird.
  if (req.request != "GET" &&
      req.request != "HEAD" &&
      req.request != "PUT" &&
      req.request != "POST" &&
      req.request != "TRACE" &&
      req.request != "OPTIONS" &&
      req.request != "DELETE") {
    return (pipe);
  }

  # sadece GET ve HEAD isteklerini cache'le
  if (req.request != "GET" && req.request != "HEAD") {
    return (pass);
  }

  # auth istiyorsa cache'leme
  if (req.http.Authorization) {
    return (pass);
  }

  # belirli URL prefix'ine sahip olanları cache'leme
  if (req.url ~ "^/admin" ||
      req.url ~ "^/ajax"
  ) {
    return (pass);
  }

  # eger belirli bir cookie varsa cache'leme
  if (req.http.cookie && req.http.cookie ~ "logged_in") {
    return (pass);
  }

  # geri kalan tum istekleri cache'le
  return(lookup);
}

sub vcl_fetch {

  # DEBUG: Asagida sayfanin cache durumunu bir header'a yazalim

  # session cookie'si var
  if (req.http.Cookie ~ "(logged_in)") {
    set beresp.http.X-Cacheable = "NO:Got Session";

  # bir cookie ekleniyor
  } elsif (beresp.http.set-cookie) {
    set beresp.http.X-Cacheable = "NO:Set-Cookie";

  # Varnish cache'lenemez diyor
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable";

  # Varnish cache'lenebilir diyor
  } else {
    set beresp.http.X-Cacheable = "YES";
  }

  # eger cookie set edilmisse ya da cache'lenemez bir sayfaysa
  # ya da 'Vary' header'ı '*' değerine eşitse, 2 dakika boyunca
  # bu adrese gelen hic bir istegi cache'lemeye calisma.
  if (beresp.ttl <= 0s ||
      beresp.http.set-cookie ||
      beresp.http.Vary == "*") {
        set beresp.ttl = 120s;
        return (hit_for_pass);
  }

  # eger status 200 degilse 30 saniyelik cache koy
  if (beresp.status != 200) {
    set beresp.ttl = 30s;
  }

  return (deliver);
}

sub vcl_deliver {

  # gereksiz header'lari sil
  remove resp.http.X-Powered-By;
  remove resp.http.Server;
  remove resp.http.Via;
  remove resp.http.X-Varnish;

  # DEBUG: Was a HIT or a MISS?
  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 ile ilgili önemli noktalar:

  • Varnish’in genel kullanımı, kullanıcı oturumu içermeyen sayfalar içindir. Hash algoritmasına (vcl_hash) kullanıcı session bilgisini ekleyerek cache yapmak mümkün olsa da tercih edilmez.
  • Varnish backend sunucusundan gönderilen header’lara saygı gösterir ve cache yapmasını engelleyecek bir header varsa (örneğin “Cache-Control: no-cache” ya da “Pragma: no-cache“) sayfayı cache’lemez.
  • PHP uygulamalarında, eğer herhangi bir yerde session_start() methodunu çalıştırıyorsanız sayfayı cache’leyemezsiniz. Bunun nedeni session_start() methodu çalıştırıldığında response’a 3 adet header eklenir: Set-Cookie (session id cookie’si), Cache-Control: no-store, no-cache ve Pragme: no-cache. Bu yüzden cache’lenmesini istediğiniz sayfalarda session kullanmayın.
  • Session ihtiyacı olan sayfalarda, kullanıcının giriş yapıp yapmadığını bir cookie ile belirleyebilir (örneğin kullanıcı login olduğu anda logged_in isimli bir cookie atarak) ve VCL’den “bu cookie varsa cache’leme” ayarı yapabilirsiniz.
  • Eğer kullanıcı device’ına göre değişen bir içeriğiniz varsa, backend’e isteği göndermeden önce user-agent bilgisinden faydalanarak device belirlemesi yapabilir, daha sonra bu bilgiyi hash sırasında kullanabilirsiniz. Detay
  • Bir sayfanın ne kadar süre cache’leneceğini uygulama tarafından Cache-Control header’ı göndererek belirleyebilirsiniz (örnek: Cache-Control: public, must-revalidate, max-age=60). Aynı şekilde cache’lenmesini istemediğiniz sayfalar için de Cache-Control: no-cache header’ı kullanarak cache’lemeyi engelleyebilirsiniz.
  • Gelen isteği backend’e göndermeden önce belirli cookie’leri silebilir, sadece gerekli olan cookie’leri bırakabilirsiniz. Örneğin Google Analytics için kullanılan utm__ cookie’lerini backend’e göndermenize gerek yok. Detay
  • Sayfalara Cache-Control header’ını kullanarak cache süresi eklediğinizde browser da bu süreye saygı gösterip süre bitene kadar sayfayı cache’ler. Eğer bunu istemiyorsanız vcl_deliver methodunda “set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";” şeklinde bir header ekleyerek browser’ın cache yapmasını engelleyebilirsiniz.