技术架构

HTTP协议缓存和CDN以及varnish

2018-09-03  本文已影响129人  Net夜风

一、简述http协议缓存原理及常用首部讲解

二、简述回源原理和CDN常见多级缓存

  1. CDN:缓存网络,Content Delivery Network,即内容分发网络;加速器,向代理缓存。
  2. 基本思路:尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器器所构成的在现有的互联网基础之上的一层只能虚拟网络,CDN系统能够实现实时的根据网络流量和各个节点的连接、负载状况以及到永固的距离和相应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用胡可就近取得所需内容,解决互联网拥挤状况,提高用户访问网站的响应速度。
  3. 基本原理:广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。
  4. 服务模式:内容分发网络(CDN)是一种新型网络构建方式,它是为能在传统的IP网发布宽带丰富媒体而特别优化的网络覆盖层;而从广义的角度,CDN代表了一种基于质量与秩序的网络服务模式。
    简单地说,内容分发网络(CDN)是一个经策略性部署的整体系统,包括分布式存储、负载均衡、网络请求的重定向和内容管理4个要件,而内容管理和全局的网络流量管理(Traffic Management)是CDN的核心所在。通过用户就近性和服务器负载的判断,CDN确保内容以一种极为高效的方式为用户的请求提供服务。
    总的来说,内容服务基于缓存服务器,也称作代理缓存(Surrogate),它位于网络的边缘,距用户仅有"一跳"(Single Hop)之遥。同时,代理缓存是内容提供商源服务器(通常位于CDN服务提供商的数据中心)的一个透明镜像。这样的架构使得CDN服务提供商能够代表他们客户,即内容供应商,向最终用户提供尽可能好的体验,而这些用户是不能容忍请求响应时间有任何延迟的。
  5. GSLB:全局服务负载均衡器; 调度客户请求到不同的缓存服务器上;
  6. SLB:局部负载均衡器;

三、varnish

官方站点:http://www.varnish-cache.org

1.varnish架构:
varnish.png

...

2. varnish的程序环境

DEAMON_OPTS DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"

-p param=value:设定运行参数及其值; 可重复使用多次; -r param[,param...]: 设定指定的参数为只读状态;

示例:
[root@localhost ~]# cat /usr/lib/systemd/system/varnish.service 
[Unit]
Description=Varnish Cache, a high-performance HTTP accelerator
After=network.target    
[Service]   
... 
EnvironmentFile=/etc/varnish/varnish.params #先加载环境文件;加载后里面的变量名就可直接调用了;  
Type=forking
PIDFile=/var/run/varnish.pid
PrivateTmp=true
ExecStart=/usr/sbin/varnishd \  #启动varnish
    -P /var/run/varnish.pid \   #指明pid文件
    -f $VARNISH_VCL_CONF \    #指明vcl配置文件,此处的变量就是在环境文件中定义的变量;
    -a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
    -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \
    -S $VARNISH_SECRET_FILE \
    -u $VARNISH_USER -g $VARNISH_GROUP \
    -s $VARNISH_STORAGE \
    $DAEMON_OPTS   #表示为除以上常见选项外的变量; 
ExecReload=/usr/sbin/varnish_reload_vcl 
[Install]
WantedBy=multi-user.target

...

[root@localhost ~]# cat /etc/varnish/varnish.params    #这里定义的其实都是命令行选项:可查看unit file文件就可明白 /usr/lib/systemd/system/varnish.service
RELOAD_VCL=1 表示systemctl使用reload而不是restart命令时,会自动重新装载vcl配置文件,就是使vcl新配置文件生效; 
VARNISH_VCL_CONF=/etc/varnish/default.vcl 设置如何加载缓存策略配置文件;此路径可自定义;   
# VARNISH_LISTEN_ADDRESS=192.168.1.5 监听的地址;默认监听所有ipv4和v6地址;如果只期望监听在一个地址上时看,可启用;
VARNISH_LISTEN_PORT=6081 用来提供服务的监听端口,varnish常作为web服务的反代,所以要改为80;但实际varnish不会真正面向客户端,而面向的是代理服务器有可能是lvs或nginx,一般是nginx或ha proxy居多,nginx和ha proxy是可以直接支持端口映射的,类似于nat机制;所以,使用6081也没什么问题;    
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 为varnish的管理接口地址; 
VARNISH_ADMIN_LISTEN_PORT=6082 为varnish管理监听的端口; 
VARNISH_SECRET_FILE=/etc/varnish/secret 为varnish连接时要求认证,是预共享密钥文件,是由varnish自己生成的密钥;  
VARNISH_STORAGE="file,/var/lib/varnish/varnish_storage.bin,1G" 为varnish缓存的存储格式为file方式存储,为二进制格式文件,1G是大小;VARNISH_STORAGE只是一个被unit file文件调用的变量名而已,跟varnish没有关系;    
VARNISH_TTL=120 如果后端服务器没指明生存时长,就为此处的默认值;    
VARNISH_USER=varnish 运行varnish进程的用户名、组名;
VARNISH_GROUP=varnish   
#DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300" 指定额外的变量;还可指定很多变量,可使用man varnishd查看;例如可指明的选项有acceptor_sleep_max、ban_lurker_age、 ban_lurker_batch等等;
    其中:Run-Time Parameters运行时参数包括很多:
    thread_pools 线程池个数,需要定义;
        Default: 2 默认为2个;
        Minimum: 1 最少为1个;
    thread_pool_min 定义每个线程池中的最少个数;
        Default: 100 默认为100个;
        Maximum: 5000 最多为5000个;
    thread_pool_max 定义每个线程池中的最多个数;
        Default: 5000 默认为5000个;
        Minimum: 100 最少为100个;
    这些运行时参数,都可以使用-p param=value指定;
3. VCL:varnish configuration language;
Varnish Finite State Machine
  1. 其中一种响应方式有可能是不运行客户端访问,直接拒绝;
  2. 还有可能的第二种方式,请求进来时分析发现,是正常请求,于是判断资源类型的是否是可缓存的,如果是可缓存的,例如用户请求的get方法,因为get方法是可以查缓存的,就开始查找缓存,如果缓存命中了直接返回给客户端;
  3. 如果发现请求的资源类型缓存未命中,则varnish要到后端服务器读取,取回来之后在响应给客户端;
  4. 如果发现请求的资源类型是不可缓存的,因为用post或put方法就不可缓存,于是直接到后端服务器读取;例如上传一个文件或提交一个表单;后端服务器响应给varnish后,再响应给客户端;
示例:obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次数;
        [root@localhost ~]# vim /etc/varnish/default.vcl 
            #在其中sub vcl_deliver {...}段中添加如下内容
            if (obj.hits>0) {
                    set resp.http.X-Cache = "HIT via " + server.ip;
                } else {
                    set resp.http.X-Cache = "MISS via " + server.ip;
                }      
        
        [root@localhost ~]# varnishadm
        vcl.load test2 default.vcl
        200        
        VCL compiled.
        vcl.list
        200
        active          0 test1
        available       0 test2
        vcl.use test2
        vcl.use test2
        200        
        VCL 'test2' now active
vcl变量可用范围.png

@R/W:能读能修改;R:只读;

示例:强制对某资源的请求不检查缓存
    #在BE主机上添加2个路径和index.html资源
    [root@rs1 ~]# mkdir /var/www/html/{admin,login}
    [root@rs1 ~]# ls /var/www/html
    admin  index.html  login
    [root@rs1 ~]# vim /var/www/html/admin/index.html
        <h1>Admin App</h1>
    [root@rs1 ~]# vim /var/www/html/login/index.html
        <h1>Login App</h1>
    #在varnish主机上修改配置文件
    [root@localhost varnish]# vim default.vcl
    #在 sub vcl_recv{...}中添加如下内容
        if (req.url ~ "(?i)^/(login|admin)") {
            return(pass);
        }
    #回到varnish命令行:使vcl配置生效
    
    [root@localhost ~]# varnishadm
    vcl.load test3 default.vcl
    200        
    VCL compiled.
    vcl.list
    200   
    available       0 test1
    active          0 test2
    available       0 test3
    vcl.use test3
    vcl.use test3
    200        
    VCL 'test3' now active

访问测试:


admin-x-cache.png
示例:不能使用curl访问
    #在varnish主机上修改配置文件
    [root@localhost varnish]# vim default.vcl
    #在 sub vcl_recv{...}中添加如下内容
        if (req.http.User-Agent ~ "(?i)curl") {
            return(synth(406));
            }
    #回到varnish命令行:使vcl配置生效
    [root@localhost ~]# varnishadm
    vcl.load test4 default.vcl
    200        
    VCL compiled.       
    vcl.use test4
    200        
    VCL 'test4' now active
    
    #client使用curl访问测试
    [root@localhost ~]# curl http://192.168.1.22
    <!DOCTYPE html>
    <html>
      <head>
        <title>406 Not Acceptable</title>
      </head>
      ...

...

示例:对于特定的资源,例如公开的图片等取消其私有标识,并强行设定其可以由varnish缓存时长
    #在BE主机上准备图片
    [root@rs1 ~]# find /usr/share -iname "*.jpg" -exec cp {} /tmp/image/ \;     
    #修改varnish的vcl配置,在default.vcl中的sub vcl_backend_response {...}中添加如下内容
     if (beresp.http.cache-control !~ "(?i)s-maxage") {
        if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)") {
                unset beresp.http.Set-Cookie;
                set beresp.ttl=3600s;
                }
        }
     #回到varnish命令行:使vcl配置生效
    vcl.load test1 default.vcl
    200        
    VCL compiled.
    vcl.list
    200        
    available       0 boot
    active          0 reload_2018-09-02T21:33:43
    available       0 test1
    
    vcl.use test1
    200        
    VCL 'test1' now active

使用client访问测试:


vcl-1.png
示例:使BE主机访问日志里记录client的真实ip地址
        #在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;
                }
        }
        #回到varnish命令行:使vcl配置生效
        vcl.load test2 default.vcl
        200        
        VCL compiled.
        vcl.use test2
        200        
        VCL 'test2' now active
        vcl.list
        200        
        available       0 boot
        available       0 reload_2018-09-02T21:33:43
        available       0 test1
        active          0 test2
    #修改BE主机的访问日志格式
    [root@rs1 conf]# vim httpd.conf
         LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    #使用client访问后查看access_log
    [root@rs1 conf]# tail -2 /var/log/httpd/access_log
    192.168.1.109.192.168.1.109 - - [02/Sep/2018:20:21:31 +0800] "GET / HTTP/1.1" 200 26 "-" "curl/7.29.0"
    192.168.1.113.192.168.1.113 - - [02/Sep/2018:20:24:10 +0800] "GET / HTTP/1.1" 200 26 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"

client使用浏览器访问测试:


vcl2.png vcl3.png
示例2:
    import directors;    # load the directors

            backend server1 {
                .host = "192.168.147.130";
                .port = "80";
            }
            backend server2 {
                .host = "192.168.147.131";
                .port = "80";
            }

            sub vcl_init {
                new servers = directors.round_robin();
                servers.add_backend(server1);
                servers.add_backend(server2);
            }

            sub vcl_recv {
                # send all traffic to the bar director:
                set req.backend_hint = servers.backend();
            }
            vcl.load test9 default.vcl
            200        
            VCL compiled.
            vcl.use test9
            200        
            VCL 'test9' now active
上一篇下一篇

猜你喜欢

热点阅读