Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

We're experiencing a strange problem with our current Varnish configuration.

4x Web Servers (IIS 6.5 on Windows 2003 Server, each installed on a Intel(R) Xeon(R) CPU E5450 @ 3.00GHz Quad Core, 4GB RAM)

3x Varnish Servers (varnish-3.0.3 revision 9e6a70f on Ubuntu 12.04.2 LTS - 64 bit/precise, Kernel Linux 3.2.0-29-generic, each installed on a Intel(R) Xeon(R) CPU E5450 @ 3.00GHz Quad Core, 4GB RAM)

The Varnish Servers performance are awfully bad in general, to the point that if we shut down one of them the other two are unable to fullfill all the requests and start to skip beats resulting in pending requests, timeouts, 404, etc.

What can we do to improve our Varnish performance? Considering that we're getting less than 5k request per seconds during our max peak, we should be able to serve our pages even with a single one of them without any problem.

We use a standard, vanilla CFG, as shown by this varnishadm >param.show output:

acceptor_sleep_decay        0.900000 []
acceptor_sleep_incr         0.001000 [s]
acceptor_sleep_max          0.050000 [s]
auto_restart                on [bool]
ban_dups                    on [bool]
ban_lurker_sleep            0.010000 [s]
between_bytes_timeout       60.000000 [s]
cc_command                  "exec gcc -std=gnu99 -g -O2 -pthread -fpic -shared -                                                                                                                               Wl,-x -o %o %s"
cli_buffer                  8192 [bytes]
cli_timeout                 20 [seconds]
clock_skew                  10 [s]
connect_timeout             0.700000 [s]
critbit_cooloff             180.000000 [s]
default_grace               10.000000 [seconds]
default_keep                0.000000 [seconds]
default_ttl                 120.000000 [seconds]
diag_bitmap                 0x0 [bitmap]
esi_syntax                  0 [bitmap]
expiry_sleep                1.000000 [seconds]
fetch_chunksize             128 [kilobytes]
fetch_maxchunksize          262144 [kilobytes]
first_byte_timeout          60.000000 [s]
group                       varnish (113)
gzip_level                  6 []
gzip_memlevel               8 []
gzip_stack_buffer           32768 [Bytes]
gzip_tmp_space              0 []
gzip_window                 15 []
http_gzip_support           off [bool]
http_max_hdr                64 [header lines]
http_range_support          on [bool]
http_req_hdr_len            8192 [bytes]
http_req_size               32768 [bytes]
http_resp_hdr_len           8192 [bytes]
http_resp_size              32768 [bytes]
idle_send_timeout           60 [seconds]
listen_address              :80
listen_depth                1024 [connections]
log_hashstring              on [bool]
log_local_address           off [bool]
lru_interval                2 [seconds]
max_esi_depth               5 [levels]
max_restarts                4 [restarts]
nuke_limit                  50 [allocations]
pcre_match_limit            10000 []
pcre_match_limit_recursion  10000 []
ping_interval               3 [seconds]
pipe_timeout                60 [seconds]
prefer_ipv6                 off [bool]
queue_max                   100 [%]
rush_exponent               3 [requests per request]
saintmode_threshold         10 [objects]
send_timeout                600 [seconds]
sess_timeout                5 [seconds]
sess_workspace              16384 [bytes]
session_linger              50 [ms]
session_max                 100000 [sessions]
shm_reclen                  255 [bytes]
shm_workspace               8192 [bytes]
shortlived                  10.000000 [s]
syslog_cli_traffic          on [bool]
thread_pool_add_delay       2 [milliseconds]
thread_pool_add_threshold   2 [requests]
thread_pool_fail_delay      200 [milliseconds]
thread_pool_max             2000 [threads]
thread_pool_min             5 [threads]
thread_pool_purge_delay     1000 [milliseconds]
thread_pool_stack           unlimited [bytes]
thread_pool_timeout         300 [seconds]
thread_pool_workspace       65536 [bytes]
thread_pools                2 [pools]
thread_stats_rate           10 [requests]
user                        varnish (106)
vcc_err_unref               on [bool]
vcl_dir                     /etc/varnish
vcl_trace                   off [bool]
vmod_dir                    /usr/lib/varnish/vmods
waiter                      default (epoll, poll)

This is our default.vcl file: LINK

sub vcl_recv {

        # BASIC recv COMMANDS:
        #
        # lookup -> search the item in the cache
        # pass -> always serve a fresh item (no-caching)
        # pipe -> like pass but ensures a direct-connection with the backend (no-cache AND no-proxy)

        # Allow the backend to serve up stale content if it is responding slow.
        # This defines when Varnish should use a stale object if it has one in the cache.
        set req.grace = 30s;

        if (client.ip == "127.0.0.1") {
                # request from NGINX - do not alter X-Forwarded-For
                set req.http.HTTPS = "on";
        }
        else {
                # Add an X-Forwarded-For to keep track of original request
                unset req.http.HTTPS;
                unset req.http.X-Forwarded-For;
                set req.http.X-Forwarded-For = client.ip;
        }
        set req.backend = www_director;

        # Strip all cookies to force an anonymous request when the back-end servers are down.

        if (!req.backend.healthy) {
          unset req.http.Cookie;
        }

        ## HHTP Accept-Encoding
        if (req.http.Accept-Encoding) {
                if (req.http.Accept-Encoding ~ "gzip") {
                        set req.http.Accept-Encoding = "gzip";
                }
                else if (req.http.Accept-Encoding ~ "deflate") {
                        set req.http.Accept-Encoding = "deflate";
                }
                else {
                        unset req.http.Accept-Encoding;
                }
        }

        if (req.request != "GET" &&
            req.request != "HEAD" &&
            req.request != "PUT" &&
            req.request != "POST" &&
            req.request != "TRACE" &&
            req.request != "OPTIONS" &&
            req.request != "DELETE") {
            /* non-RFC2616 or CONNECT */
               return (pipe);
        }

        if (req.request != "GET" && req.request != "HEAD") {
          /* only deal with GET and HEAD by default */
          return (pass);
        }

        if (req.http.Authorization) {
          return (pass);
        }

        if (req.http.HTTPS ~ "on") {
          return (pass);
        }


######################################################
# COOKIE HANDLING
######################################################

# METHOD 1: do not remove cookies, but pass the page if they contain TB_NC

        if (!(req.url ~ "(?i)\.(png|gif|ipeg|jpg|ico|swf|css|js)(\?[a-z0-9]+)?$")) {
                if (req.http.Cookie && req.http.Cookie ~ "TB_NC") {
                        return (pass);
                }
        }
        return (lookup);
}


# Code determining what to do when serving items from the IIS Server

sub vcl_fetch {
        unset beresp.http.Server;
        set beresp.http.Server = "Server-1";
  # Allow items to be stale if needed. This is the maximum time Varnish should keep an object.
  set beresp.grace = 1h;

  if (req.url ~ "(?i)\.(png|gif|ipeg|jpg|ico|swf|css|js)(\?[a-z0-9]+)?$") {
     unset beresp.http.set-cookie;
  }

  # Default Varnish VCL logic
  if (!beresp.cacheable ||
        beresp.ttl <= 0s ||
        beresp.http.Set-Cookie ||
        beresp.http.Vary == "*") {
      set beresp.ttl = 120 s;
      return(hit_for_pass);
  }

  # Not Cacheable if it has specific TB_NC no-caching cookie
  if (req.http.Cookie && req.http.Cookie ~ "TB_NC") {
    set beresp.http.X-Cacheable = "NO:Got Cookie";
    set beresp.ttl = 120 s;
    return(hit_for_pass);
  }

  # Not Cacheable if it has Cache-Control private
  else if (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    set beresp.ttl = 120 s;
    return(hit_for_pass);
  }

  # Not Cacheable if it has Cache-Control no-cache or Pragma no-cache
  else if (beresp.http.Cache-Control ~ "no-cache" || beresp.http.Pragma ~ "no-cache") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=no-cache (or pragma no-cache)";
    set beresp.ttl = 120 s;
    return(hit_for_pass);
  }

  # If we reach to this point, the object is cacheable.

  # Cacheable but with not enough ttl: we need to extend the lifetime of the object artificially
  # NOTE: Varnish default TTL is set in /etc/sysconfig/varnish
  #       and can be checked using the following command:
  #       varnishadm param.show default_ttl

  else if (beresp.ttl < 1s) {
    set beresp.ttl   = 5s;
    set beresp.grace = 5s;
    set beresp.http.X-Cacheable = "YES:FORCED";
  }

  # Cacheable and with valid TTL.
  else {
    set beresp.http.X-Cacheable = "YES";
  }

# DEBUG INFO (Cookies)
# set beresp.http.X-Cookie-Debug = "Request cookie: " + req.http.Cookie;
  return(deliver);
}

sub vcl_error {
    set obj.http.Content-Type = "text/html; charset=utf-8";
    if (obj.status == 404) {
        synthetic {"
            <!-- Markup for the 404 page goes here -->
        "};
    }
    else if (obj.status == 500) {
        synthetic {"
            <!-- Markup for the 500 page goes here -->
        "};
    }
    else if (obj.status == 503) {
      if (req.restarts < 4) { return(restart); }
      else {
         synthetic {"
             <!-- Markup for the 503 page goes here -->
         "};
      }
    }
    else {
        synthetic {"
            <!-- Markup for a generic error page goes here -->
        "};
    }
}

sub vcl_deliver {
    if (obj.hits > 0) {
      set resp.http.X-Cache = "HIT";
    } else {
      set resp.http.X-Cache = "MISS";
    }
}

Thanks in advance,

share|improve this question
1  
Have you profiled disk IO on the varnish boxes? –  Chainik Sep 27 '13 at 13:51
1  
How's varnishhist look on these? –  Shane Madden Sep 27 '13 at 20:58
1  
Do you store on disk or RAM? Additionally I would assume that the cache hit rate is quite slow so Varnish isn't able to respond to requests but have to forward most of them to your web servers. I cannot see rules to force more caching in your config. –  Jens Bradler Sep 28 '13 at 9:26
2  
Do a varnishstat -1 during troubles. Show the load on your web servers. Do a debug.heatlh in varnishadm and post the output. That should be enough to get an idea. Because something is indeed very wrong in your setup if you don't have an extreme amount of traffic and extremely high cache hitrate. –  Clarence Sep 29 '13 at 21:15
    
@Chainik: we don't cache anything on disk, and iotop is showing 0.00% I/O waiting time for Varnish. I don't think HDD is the bottleneck there. @Shane Madden: the hits are as expected, and also the vast majority (90% +) even when the problem arises. @Jens Bradler: We store on RAM, and the hit-rate is very high. @Clarence: Will do it today and post it in the OP. –  Darkseal Nov 20 '13 at 11:44

1 Answer 1

up vote 1 down vote accepted

You haven't posted the one useful thing to address performance issues; "varnishstat -1". So, here are some general advice.

  • Increase min_threads so Varnish can have some threads lying around.
  • Mount /var/lib/varnish on tmpfs (Linux writes shared memory to disk. meh).
  • Tune the Linux TCP stack
  • Make sure the hit rate is high
share|improve this answer
    
thanks, will do it and post an update. –  Darkseal Jun 13 at 9:02

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.