Varnish on Centos

Varnish on CentOs
Que es Varnish??? Si quieres instalarlo seguro que ya sabes lo que es y para que sirve…
 Nosotros vamos a utilizar Varnish como proxy inverso (reverse-proxy) de contenido estático, pero este “Open Source”  está diseñado  como acelerador de contenidos, ya sea estático o dinámico. De momento solo vamos a utilizarlo como cache de imágenes, de nuestro portal.
La instalación es sencilla, pero tendremos que familiarizarnos con su propio lenguaje de VCL http://www.varnish-cache.org/trac/wiki/VCL, luego explicare el fichero de configuración que tenemos aplicado en nuestro sistema.
La estructura, tenemos dos servidores Varnish, que atienden por el puerto 80 (estos dos server están balanceado) a su vez tenemos dos backend que contienen los repositorios de imágenes, que responden al puerto 81 con un LighttpD sobre Windows.
Desglose técnico:
Varnish Server:
PROXY01 -> CentOs 5.6 kernel 2.6.18-238.9.1.el5 x64 – 12 GB RAM – 136 GB disco.
PROXY02 -> CentOs 5.6 kernel 2.6.18-238.9.1.el5 x64 – 12 GB RAM – 136 GB disco.
Backend Server:
IMG01 -> Windows 2008 Enterprise R2 x64 – 9 GB RAM – 1.5 TB imágenes (1 TB ocupado)
IMG02 -> Windows 2008 Enterprise R2 x64 – 9 GB RAM – 1.5 TB imágenes (1 TB ocupado)
Storage System:
Cabina de disco HP EVA 4400 (fibra SCSI), conexión por fibra a los backend.

                           



Una vez ya sabemos cómo tenemos construido el sistema, vamos a proseguir con la instalación y configuración del sistema.
Instalación, tenemos que isntalar el repositorio de varnish para poder realizer un yum install.
[#] rpm --nosignature -i http://repo.varnish-cache.org/redhat/el5/noarch/varnish-release-2.1-2.noarch.rpm
[#] yum install varnish
Ya tenemos la instalación de Varnish, dejamos activado el autoarranque del servidor y de los sistemas de LOG.
[#] chkconfig varnish on
[#] chkconfig varnishlog on
[#] chkconfig varnishncsa on
Los tiene dos servicios de log los cuales se guardan en /var/log/varnish/ tenemos  el  varnishlog es el propio sistema de log, con formato Varnish, nos muestra el flujo de las peticiones, lo podemos utilizar en consola.
[#] varnishlog

   16 TxHeader     b Accept-Encoding: gzip, deflate
   16 TxHeader     b Host: images.
   16 TxHeader     b X-Varnish: 705369720
   16 RxProtocol   b HTTP/1.1
   16 RxStatus     b 200
   16 RxResponse   b OK
   16 RxHeader     b Content-Type: image/jpeg
   16 RxHeader     b Accept-Ranges: bytes
   16 RxHeader     b ETag: "2884099485"
   16 RxHeader     b Last-Modified: Sun, 01 May 2011 10:52:54 GMT          
   16 RxHeader     b Content-Length: 1901
   16 RxHeader     b Connection: close
   16 RxHeader     b Date: Mon, 02 May 2011 10:21:53 GMT
   16 RxHeader     b Server: LightTPD/1.4.28 (Win32)
   18 TTL          c 705369720 RFC 120 1304331713 0 0 0 0
   18 VCL_call     c fetch
   18 TTL          c 705369720 VCL 604800 1304331713
   18 VCL_return   c deliver
   18 ObjProtocol  c HTTP/1.1
   18 ObjStatus    c 200
   18 ObjResponse  c OK
   18 ObjHeader    c Content-Type: image/jpeg
   18 ObjHeader    c ETag: "2884099485"
   18 ObjHeader    c Last-Modified: Sun, 01 May 2011 10:52:54 GMT         
   18 ObjHeader    c Date: Mon, 02 May 2011 10:21:53 GMT
   18 ObjHeader    c Server: (Win32)
   18 ObjHeader    c X-Cacheable: YES
   18 ObjHeader    c cache-control: max-age = 2592000

Y el varnishncsa sistema de log con formato web, lo podemos comprobar mediante
[#] tail –f /var/log/Varnish/Varnishncsa.log
172.xx.xx.xx - - [02/May/2011:12:30:38 +0200] "GET /test.jpg " 400 349 "-" "-"

Es recomendable modificar la configuración del  logrotate  para que cambien los log a diario  vi /etc/logrotate.conf
[#] vi /etc/logrotate.conf

# see "man logrotate" for details
# rotate log files weekly
daily
# keep 4 weeks worth of backlogs
rotate 7
Almacenamiento de Varnish.

Tenemos dos opciones para almacenar en cache los objetos, uno es utilizar la memoria RAM, este tiene la ventaja que trabaja más rápido que el disco y la desventaja  necesitamos mucha memoria RAM si queremos tener una gran numero de objetos cacheados. La otra opción es utilizar disco físico como almacenamiento, esta opción está muy bien pensada porque por lo contrario de otros sistemas reverse-proxy, Varnish utiliza un único fichero con la capacidad que le indiquemos y lo gestiona de una manera óptima e indexada.

En la configuración explicare como utilizar una opción o la otra, todo dependerá de nuestros requisitos, nosotros hemos utilizado la opción de disco  con particiones ext4 porque este formato de disco optimiza los fichero de gran tamaño.

En CentOs, a partir de la versión 5.6 es totalmente compatible el formato ext4 una vez tenemos instalado la versión correcta, instalamos la herramienta de para dar formato a nuestra partición.

[#] yum -y install e4fsprogs
Como no tenemos la posibilidad de tener dos disco en RAID-1 para el servidor, hemos realizado dos particiones sobre el RAID-1 de 136 GB,  la partición /cache_disk  la utilizaremos solo para almacén de objetos.
[#] df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/cciss/c0d0p1      21G  2.5G   17G  13% /
/dev/cciss/c0d0p2      98G  2.3G   91G   3% /cache_disk
tmpfs     

Vamos a desmontar c0d0p2.
[#] umount /dev/cciss/c0d0p2

Le damos formato a la partición.
[#] tune4fs -O extents,uninit_bg,dir_index /dev/cciss/c0d0p2
Optimización de la partición.
[#] e4fsck -fDC0 /dev/cciss/c0d0p2
Tenemos que configurar el fichero fstab para dejar los cambios en el inicio.
[#] vi /etc/fstab
Tenemos que realizar la siguientes modificaciones, quitar LABEL=/cache_disk y ponemos /dev/cciss/c0d0p2, cambiar ext3  por ext4 y para el Varnish poner las opciones  noatime,nodiratime la configuración nos quedaría de la siguiente manera.
/dev/cciss/c0d0p2 /cache_disk  ext4  defaults,noatime,nodiratime   1 2
Volvemos a montar la unidad y reiniciamos para comprobar que todo funciona OK.
[#] mount /dev/cciss/c0d0p2
Configuración Varnish
Ya tenemos instalado Varnish y preparado el servidor para realizar la configuración, lo primero que tenemos que conocer son los tres ficheros de configuración de Varnish.
Fichero de configuración del servidor Varnish
[#] vi /etc/sysconfig/varnish
----------------------------------------------------------------------
# Configuration file for varnish
#
# /etc/init.d/varnish expects the variable $DAEMON_OPTS to be set from this
# shell script fragment.
#

# Maximum number of open files (for ulimit -n)
NFILES=131072
# Locked shared memory (for ulimit -l)
# Default log size is 82MB + header
MEMLOCK=82000
# # Main configuration file. You probably want to change it :)
VARNISH_VCL_CONF=/etc/varnish/myconfig.vcl
#
# # Default address and port to bind to
# # Blank address means all IPv4 and IPv6 interfaces, otherwise specify
# # a host name, an IPv4 dotted quad, or an IPv6 address in brackets.
# VARNISH_LISTEN_ADDRESS=
VARNISH_LISTEN_PORT=80
#
# # Telnet admin interface listen address and port
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
#
# # Shared secret file for admin interface
VARNISH_SECRET_FILE=/etc/varnish/secret
#
# # The minimum number of worker threads to start
VARNISH_MIN_THREADS=1
#
# # The Maximum number of worker threads to start
VARNISH_MAX_THREADS=1000
#
# # Idle timeout for worker threads
VARNISH_THREAD_TIMEOUT=120
#
# # Cache file location
VARNISH_STORAGE_FILE=/cache_disk/varnish_storage.bin
#
# # Cache file size: in bytes, optionally using k / M / G / T suffix,
# # or in percentage of available disk space using the % suffix.
VARNISH_STORAGE_SIZE=90G
# # Cache memory size: same that Storage_file
VARNISH_MEMORY_SIZE=10G
#
# # Backend storage specification
VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}"
#
# # Default TTL used when the backend does not specify one
VARNISH_TTL=120
#
# # DAEMON_OPTS is used by the init script.  If you add or remove options, make
# # sure you update this section, too.
DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
             -f ${VARNISH_VCL_CONF} \
             -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
             -t ${VARNISH_TTL} \
             -w ${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
             -u varnish -g varnish \
             -S ${VARNISH_SECRET_FILE} \
             -s ${VARNISH_STORAGE} \
           # -s malloc,${VARNISH_MEMORY_SIZE} \
           -p obj_workspace=4096 \
           -p sess_workSpace=262144 \
           -p listen_depth=4096 \
           -p overflow_max=2000 \
           -p ping_interval=2 \
           -p log_hashstring=off \
           -h classic,5000009 \
           -p thread_pool_max=4000 \
           -p lru_interval=20 \
           -p esi_syntax=0x00000003 \
           -p sess_timeout=2 \
           -p thread_pools=4 \
           -p thread_pool_min=400 \
           -p shm_workspace=32768 \
           -p srcadd_ttl=0 \
           -p thread_pool_add_delay=2"

Que hemos configurado,
VARNISH_VCL_CONF=/etc/varnish/myconfig.vcl
Que fichero vamos a utilizar para la configuración  del proxy, este fichero lo explicaremos más adelante.
VARNISH_STORAGE_FILE=/cache_disk/varnish_storage.bin
Donde vamos a ubicar el fichero de cache, este fichero lo ubicamos en la partición ext4 que hemos creado anteriormente, el acceso y rendimiento es óptimo.
VARNISH_STORAGE_SIZE=90G
El espacio disponible que damos al Varnish para que almacene objetos.
VARNISH_MEMORY_SIZE=10G
Si utilizamos la memoria como almacén de objetos, esta será la memoria que utilizara, en nuestro caso no lo utilizamos, esto lo indicamos.
             -s ${VARNISH_STORAGE} \
           # -s malloc,${VARNISH_MEMORY_SIZE} \

Ahora vamos a ver la configuración del daemon  DAEMON_OPTS
                     -p obj_workspace=4096 \
           -p sess_workSpace=262144 \
           -p listen_depth=4096 \
           -p overflow_max=2000 \
           -p ping_interval=2 \
           -p log_hashstring=off \
           -h classic,5000009 \
           -p thread_pool_max=4000 \
           -p lru_interval=20 \
           -p esi_syntax=0x00000003 \
           -p sess_timeout=2 \
           -p thread_pools=4 \
           -p thread_pool_min=400 \
           -p shm_workspace=32768 \
           -p srcadd_ttl=0 \
           -p thread_pool_add_delay=2"
Esta optimizada la configuración para el servidor con 2 Procesadores Intel DualCore x64.
thread_pool_add_delay=2
thread_pools = <Number of cpu cores>
thread_pool_min = <800/number of cpu cores>
thread_pool_max = 4000

Ya tenemos configurado el servidor, ahora tenemos que configurar el servicio, aquí entra en juego el lenguaje propio del Varnish VCL, nuestra configuración es muy sencilla solo reverse-proxy de imágenes.
Configuración VLC
[#] vi /etc/Varnish/inmesp.vcl

## This is a basic VCL configuration file for varnish. 
#
## Backend definition. 
# set default backend if no server cluster specified
backend inmesp_default {
    .host = "img01";
    .port = "81";
      .probe = {
    .url = "/test.jpg";
    .interval = 10s;
    .timeout = 5 s;
    .window = 5;
    .threshold = 3;
      }
}

# create a round-robin director: "images_cluster" uses server1 and server2 as backend servers.
director inmesp_cluster round-robin {
  { .backend = {
      .host = "img01";
      .port = "81";
      .probe = {
    .url = "/test.jpg";
    .interval = 5s;
    .timeout = 1 s;
    .window = 5;
    .threshold = 3;}
      }
  }
  { .backend = {
      .host = "img02";
      .port = "81";
      .probe = {
    .url = "/test.jpg";
    .interval = 5s;
    .timeout = 1 s;
    .window = 5;
    .threshold = 3;}
      }
   }
}
## Only permit cluster to purge files from cache
acl purge {
      "proxy01";
      "proxy02";
      }

## vcl_recv is called whenever a request is received
sub vcl_recv {
# This uses the ACL action called "purge". Basically if a request to
# PURGE the cache comes from anywhere other than localhost, ignore it.
        if (req.request == "PURGE")
            {if (!client.ip ~ purge)
                {error 405 "Not allowed.";}
            return (lookup);}
# Serve objects up to 2 minutes past their expiry if the backend
# is slow to respond.
    set req.grace = 120s;

# Use our round-robin "inmesp_cluster" cluster for the backend.
# Use "inmesp_default" for one only backend
        if (req.http.host ~ "^images.domain.com$")
           {set req.backend = inmesp_default;}
        else
           {set req.backend = inmesp_cluster;}

## Cache based on file path - if it's in /images/, it probably
## doesn't change much.
    if (req.request == "GET" && req.url ~ "^/PATH1|/PATH2") {
        unset req.http.cookie;
        return (lookup);}
        else{return (pass);}
## If your app has a less predictable layout - you can instead
## cache based on file extension - be sure to update vcl_fetch
## if you use this method.
#if (req.request == "GET" && req.url~ "\.(gif|jpg|jpeg|png|tiff|tif|ico)$") {
#    unset req.http.cookie;
#    return (lookup);
#}

    return (lookup);
}

# Called if the cache has a copy of the page.
sub vcl_hit {
        if (req.request == "PURGE")
            {purge_url(req.url);
            error 200 "Purged";}
}
# Called if the cache does not have a copy of the page.
sub vcl_miss {
        if (req.request == "PURGE")
           {error 200 "Not in cache";}
}

# Called after a document has been successfully retrieved from the backend.
sub vcl_fetch {

# set minimum timeouts to auto-discard stored objects
    set beresp.grace = 120s;

    if (req.request == "GET" && req.url ~ "^/inmogeo|/inmesp" ) {
            unset beresp.http.Set-cookie;
            set beresp.http.X-Cacheable = "YES";
            set beresp.cacheable = true;}

## How to cache things longer on Varnish than on the client
            if (beresp.cacheable) {
            # Remove Expires from backend, it's not long enough
            unset beresp.http.expires;
            # Set the clients TTL on this object
            set beresp.http.cache-control = "max-age = 2592000";
            # Set how long Varnish will kepp it
            set beresp.ttl = 1w;
            # marker for vcl_deliver to reset Age:
            set beresp.http.magicmarker = "1";

            return (deliver);
            }

    #if (req.request == "GET" &&
    #    req.url ~ "\.(gif|jpg|jpeg|png|tiff|tif|ico)$" ) {
      #           unset beresp.http.set-cookie;
      #           set beresp.http.X-Cacheable = "YES";
      #           set beresp.cacheable = true;
      #       return (deliver);
      #        }
## Don't cache anything that is not a 20x response.  We don't want
## to cache errors.  If you want to cache redirects, you
## can set this to be higher than 300 (temporary redirects are 302)
    if (beresp.status >= 300) {
        return (pass);
    }
    
    ## if varnish thinks it's not cachable, don't cache it.
    if (!beresp.cacheable) {
        return (pass);
    }
        
    return (pass);
}
sub vcl_deliver {
            ## Add cache hit data
            if (obj.hits > 0) {
                  #if hit add hit count
            set resp.http.X-Cache = "HIT";
            set resp.http.X-Cache-Hits = obj.hits;}
            else {
                  set resp.http.X-Cache = "MISS";}
            ## How to cache things longer on Varnish than on the client
            if (resp.http.magicmarker) {
                  # Remove the magic marker
                  unset resp.http.magicmarker;
                  # By definition we have a fresh object
                  set resp.http.age = "0";
                  set resp.http.X-Age = resp.http.Age;
                  unset resp.http.Age;
                  unset resp.http.Server;
                  unset resp.http.X-Served-By;
                  set resp.http.X-Served-By = "proxy01";}
}
# Called if the cache has a copy of the page.
sub vcl_hit {
        if (req.request == "PURGE")
            {purge_url(req.url);
            error 200 "Purged";}
        if (!obj.cacheable) {
                  return(pass);}
}

En otro momento explicare que significa cada configuración que hemos realizado, aunque no tiene mucha complicación. ()
Fichero secret, en este fichero tenemos que poner la contraseña para poder acceder al Varnish desde consola
[#] vi /etc/Varnish/secret
Tuning Varnish
Vamos a realizar unas modificaciones para el Varnish.
[#] vi /etc/sysctl.conf

net.ipv4.ip_local_port_range = 1024 65536
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
net.ipv4.tcp_fin_timeout = 3
net.ipv4.tcp_tw_recycle = 1
net.core.netdev_max_backlog = 30000
net.ipv4.tcp_no_metrics_save=1
net.core.somaxconn = 262144
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
fs.file-max = 131072
vm.swappiness = 0

# Keep Alive
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 5
Hay que añadir estos límites para el usuario Varnish
[#] /etc/security/limits.conf

@varnish                soft    nofile          131072
@varnish                hard    nofile          131072
@varnish                soft    memlock         400000
@varnish                hard    memlock         400000

Como ya habíamos modificado, la partición para la cache de objetos la tenemos en ext4 y noatime y nodiratime.

1 comentario:

Alberto dijo...

Muy buen aporte!

Gracias!