• 高性能HTTP加速器Varnish安装与配置(包含常见错误)


        Varnish是一款高性能的开源HTTP加速器。挪威最大的在线报纸Verdens Gang使用3台Varnish取代了原来的12台Squid,性能竟然比曾经更好。Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发人员之中的一个。他觉得如今的计算机比起1975年已经复杂很多。在1975年时。储存媒介仅仅有两种:内存与硬盘。但如今计算机系统的内存除了主存外,还包含了cpu内的L1、L2,甚至有L3快取。

    硬盘上也有自己的快取装置。因此Squid cache自行处理物件替换的架构不可能得知这些情况而做到最佳化。但操作系统能够得知这些情况。所以这部份的工作应该交给操作系统处理。这就是Varnish cache设计架构。眼下非常多互联网公司在使用Varnish。当中包含Facebook

    特性:

    • VCL(Varnish Configuration Language):差别于其它系统。Varnish採用了自身的配置语言来配置,很easy上手,这些配置会被编译成二进制机器码,明显加快了运行速度。
    • Health checks:完好的健康检查机制。
    • ESI(Edge Side Includes):在HTML中嵌入动态脚本文件。
    • Directors:后端server的调度方式:random,round-robin。client,hash,DNS。
    • Purging and banning:强大的缓存清除功能。能够以正則表達式的形式清除缓存。
    • Logging in Varnish:Varnish的log不是记录在文件里的,而是记录在共享内存中。

      当日志大小达到分配的共享内存容量,覆盖掉旧的日志。以这样的方式记录日志比文件的形式要快非常多,而且不须要磁盘空间。

    • 丰富的管理程序:varnishadm,varnishtop,varnishhist,varnishstat以及varnishlog等。

    环境:CentOS 6.5


    首先安装ncurses-devel,否则varnishstat,varnishtop都无法编译完毕
    yum install ncurses-devel
    安装Varnish
    wget https://repo.varnish-cache.org/source/varnish-4.0.1.tar.gz
    tar -zxvf varnish-4.0.1.tar.gz
    cd varnish-4.0.1
    ./configure --prefix=/usr/local/varnish
    make && make install
    可能会报的错: No package 'libpcre' found 错误
    解决的方法:export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig。然后继续编译

    开启Varnish
    /usr/local/varnish-2.1.5/sbin/varnishd -f /usr/local/varnish-2.1.5/etc/varnish/default.vcl -T 127.0.0.1:2000 -a 0.0.0.0:80 -s file,/tmp,200M
    当中-f用来指定配置文件,-T指定管理台的訪问地址。-a指定Varnish监听地址,-s指定Varnish以文件方式来缓存资源,地址为/tmp,大小200MB。
    可能会报的错:
    Message from VCC-compiler:
    No backends or directors found in VCL program, at least one is necessary.
    Running VCC-compiler failed, exit 1
    VCL compilation failed
    解决的方法:没有设置varnish配置文件

    配置文件(能够配置多个后端处理器,以轮询方式实现负载均衡)
    backend default {
    	.host = "127.0.0.1";
    	.port = "8080";
    	.connect_timeout = 5s;
    	.first_byte_timeout= 5s;
    	.probe = {
            #health check
            .url = "/check.txt";
            .interval = 5s;
            .timeout = 5s;
            .window = 5;
            .threshold = 3;
        }
    }
    
    sub vcl_recv {
        if (req.restarts == 0) {
    		if (req.http.x-forwarded-for) {
    		    set req.http.X-Forwarded-For =
    			req.http.X-Forwarded-For ", " client.ip;
    		} else {
    		    set req.http.X-Forwarded-For = client.ip;
    		}
        }
        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 which is weird. */
            return (pipe);
        }
        if (req.request != "GET" && req.request != "HEAD") {
            /* We only deal with GET and HEAD by default */
            return (pass);
        }
        if (req.http.Authorization || req.http.Cookie) {
            /* Not cacheable by default */
            return (pass);
        }
        return (lookup);
    }
    
    sub vcl_pipe {
        # Note that only the first request to the backend will have
        # X-Forwarded-For set.  If you use X-Forwarded-For and want to
        # have it set for all requests, make sure to have:
        # set bereq.http.connection = "close";
        # here.  It is not set by default as it might break some broken web
        # applications, like IIS with NTLM authentication.
        return (pipe);
    }
    
    sub vcl_pass {
        return (pass);
    }
    
    sub vcl_hash {
        set req.hash += req.url;
        if (req.http.host) {
            set req.hash += req.http.host;
        } else {
            set req.hash += server.ip;
        }
        return (hash);
    }
    
    sub vcl_hit {
        if (!obj.cacheable) {
            return (pass);
        }
        return (deliver);
    }
    
    sub vcl_miss {
        return (fetch);
    }
    
    sub vcl_fetch {
        if (!beresp.cacheable) {
            return (pass);
        }
        if (beresp.http.Set-Cookie) {
            return (pass);
        }
        return (deliver);
    }
    
    sub vcl_deliver {
        return (deliver);
    }
    
    sub vcl_error {
        set obj.http.Content-Type = "text/html; charset=utf-8";
        synthetic {"
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
      <head>
        <title>"} obj.status " " obj.response {"</title>
      </head>
      <body>
        <h1>Error "} obj.status " " obj.response {"</h1>
        <p>"} obj.response {"</p>
        <h3>Guru Meditation:</h3>
        <p>XID: "} req.xid {"</p>
        <hr>
        <p>Varnish cache server</p>
      </body>
    </html>
    "};
        return (deliver);
    }

    启动脚本
    wget -O varnishd https://raw.github.com/gist/3671408/3a51578bbd60a4cf8317bdc9508527b81eb23da5/varnishd
    cp varnishd /etc/init.d/varnishd
    chmod +x /etc/init.d/varnishd
    /etc/init.d/varnishd start

    Subroutine列表

    • vcl_recv 在请求開始时候被调用,在请求已经被接收到而且解析后调用。

      目的就是决定是否处理这个请求,怎么处理,使用哪个后端。vcl_recv以return结束,參数能够为例如以下keyword: 
      error code [reason]:返回错误码给client,丢弃请求。

       
      pass:转换到pass模式。

      控制权最后会转移到vcl_pass。 
      pipe:转换到pipe模式。控制权最后会转移到vcl_pipe。 
      lookup:在缓存中寻找请求对象。

      控制权最后会转移到vcl_hit或者vcl_miss。决定于对象是否在缓存中。

    • vcl_pipe 当进入pipe模式的时候被调用。

      在这个模式中,请求会被转移到后端。兴许的数据无论是从client还是后端来的都会以不变的方式传送,直到连接关闭为止。vcl_pipe以return结束,參数能够为例如以下keyword: 
      error code [reason]:返回错误码给client,丢弃请求。 
      pipe:以pipe模式运行。

    • vcl_pass 当进入pass模式的时候会被调用。在这个模式中,请求会被传送到后端,然后后端的响应会被传送回client,可是响应不会进入缓存中。接下来通过同样client连接发起的请求会以普通的方式来处理。vcl_pass以return结束。參数能够为例如以下keyword: 
      error code [reason]:返回错误码给client。丢弃请求。 
      pass:以pass模式运行。 
      restart:又一次启动这个事务。添加了重新启动计数。

      假设重新启动的次数高于max_restarts,varnish会引起一个错误。

    • vcl_hash 你假设把想把数据增加到hash中,那么调用hash_data()。vcl_hash以return结束,參数能够为例如以下keyword: 
      hash:运行hash逻辑。

    • vcl_hit 假设请求的对象在缓存中被找到了,那么在缓存查找结束后被调用。vcl_hit以return结束。參数能够为例如以下keyword: 
      deliver:deliver缓存对象到client。控制权最后会转移到vcl_deliver

       
      error code [reason]:返回错误码给client,丢弃请求。 
      pass:切换到pass模式。

      控制权最后会转移到vcl_pass。 
      restart:又一次启动这个事务。添加了重新启动计数。

      假设重新启动的次数高于max_restarts,varnish会引起一个错误。

    • vcl_miss 假设请求的对象在缓存中没有被找到,那么在缓存查找结束后被调用。

      目的是为了决定是否去后端获取这个请求对象,而且要选择哪个后端。vcl_miss以return结束,參数能够为例如以下keyword: 
      error code [reason]:返回错误码给client,丢弃请求。 
      pass:切换到pass模式。

      控制权最后会转移到vcl_pass。 
      fetch:去后端获取请求对象。控制权最后会转移到vcl_fetch

    • vcl_fetch 当一个对象被成功从后端获取的时候此方法会被调用。

      vcl_fetch以return结束,參数能够为例如以下keyword: 
      deliver:可能把对象放入缓存中,然后再deliver到client。

      控制权最后会转移到vcl_deliver。 
      error code [reason]:返回错误码给client,丢弃请求。 
      esi:以ESI形式来处理刚刚被获取到的对象。 
      pass:切换到pass模式。控制权最后会转移到vcl_pass

       
      restart:又一次启动这个事务。

      添加了重新启动计数。假设重新启动的次数高于max_restarts。varnish会引起一个错误。

    • vcl_deliver当一个缓存的对象被deliver到client的时候,此方法会被调用。vcl_deliver以return结束,參数能够为例如以下keyword: 
      deliver:发送对象到client。 
      error code [reason]:返回错误码给client,丢弃请求。 
      restart:又一次启动这个事务,添加重新启动计数。假设重新启动的次数高于max_restarts,varnish会引起一个错误。

    • vcl_error 当遇见一个错误的时候会被调用,错误可能是跟后端有关系或者内部错误。vcl_error以return结束,參数能够为例如以下keyword: 
      deliver:发送对象到client。

       
      restart:又一次启动这个事务,添加重新启动计数。假设重新启动的次数高于max_restarts。varnish会引起一个错误。

    重要变量

    subroutine不带參数,一般通过全局变量来实现信息的传递。

    例如以下变量在backend中有效:

    • .host:backend的主机名或者IP。

    • .port:backend的端口。

    例如以下变量在处理一个请求(比如vcl_recv)的时候可用:

    • client.ip:客户端IP地址。
    • server.hostname:server的主机名。
    • server.identity:server标示,当启动varnish的时候用-i參数来指定。

      假设varnish启动时候没有指定-i參数,那么server.identity会被设置为用-n參数所指定的实例名称。

    • server.ip:serverIP地址。
    • server.port:server端口。
    • req.request:请求类型(比如GETHEAD)。
    • req.url:请求的URL。

    • req.proto:HTTP协议版本号。
    • req.backend:处理请求的后端server。

    • req.backend.healthy:后端是否健康。

      health check须要在backendprobe中进行设置。

    • req.http.header:相关的HTTP头。
    • req.hash_always_miss:强迫对于本次请求的缓存查找结果为miss。假设设置为true,那么varnish将会忽略不论什么存在的缓存对象,一直从后端又一次获取资源。

    • req.hash_ignore_busy:在缓存查找时候忽略不论什么忙的对象。

      假设有两个server,彼此互相查找缓存内容,那么能够使用这个变量来避免潜在的死锁。

    例如以下变量在准备一个后端请求(比方在cache miss或者passpipe模式)的时候可用:

    • bereq.request:请求的类型(比方GETHEAD)。
    • bereq.url:请求的URL。
    • bereq.proto:与后端server交互的HTTP协议版本号。

    • bereq.http.header:相关的HTTP头。
    • bereq.connect_timeout:与后端连接的超时时间。
    • bereq.first_byte_timeout:从后端返回第一个字节所需等待的秒数,在pipe模式中不可用。
    • bereq.between_bytes_timeout:从后端返回的每一个字节之间的时间间隔,以秒计。

      pipe模式中不可用。

    例如以下的变量在请求对象从后端返回之后,在其被放入缓存之前可用。换句话说,也就是在vcl_fetch中可用。

    • beresp.proto:HTTP协议版本号。
    • beresp.status:后端返回的HTTP状态码(比如200,302等)。
    • beresp.response:后端返回的状态内容(比如OKFound)。
    • beresp.cacheable:假设请求的结果是能够被缓存的,那么此变量为true。假设HTTP状态码为200, 203, 300, 301, 302, 404,410之中的一个而且pass没有在vcl_recv中被调用。那么这个结果就是能够被缓存的。

      假设response的TTLgrace time都为0,那么beresp.cacheable将会为0。beresp.cacheable是可写的。

    • beresp.ttl:缓存对象的生存时间,以秒为单位。这个变量是可写的。

    在对象已经存在于缓存中并被查询到的时候。一般在vcl_hitvcl_deliver中。例如以下的变量(大部分是read-only)可用:

    • obj.proto:与后端交互的HTTP版本号协议。

    • obj.status:后端返回的HTTP状态码。
    • obj.response:后端返回的HTTP状态内容。

    • obj.cacheable:假设对象的beresp.cacheable为true。那么此变量的值为true。除非你强制delivery,否则obj.cacheable一直为true
    • obj.ttl:缓存对象的生存时间。以秒为单位。这个变量是可写的。
    • obj.lastuse:从如今到对象近期一次訪问所间隔的时间。以秒为单位。

    • obj.hits:对象被发送到client的次数,0表示缓存查询miss了。

    例如以下变量在决定对象hash key的时候可用:

    • req.hash:hash key被用来关联一个缓存中的对象。

      在读写缓存的时候都会被用到。

    例如以下变量在准备把一个响应发送给client时候可用:

    • resp.proto:响应使用的HTTP协议版本号。
    • resp.status:将要返回的HTTP状态码。
    • resp.response:将要返回的HTTP状态内容。
    • resp.http.header:相关的HTTP头。




  • 相关阅读:
    C++中的类模板详细讲述
    函数模板和模板函数
    vs2008 快捷键大全
    #宏定义##
    多工程项目设置
    conemu 配置
    itcast-svn
    itcast-spring-三大框架整合
    Spring通知方法错误
    动态代理
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7233284.html
Copyright © 2020-2023  润新知