架构高性能网站秘笈(四)——反向代理缓存

什么是反向代理?

在介绍“反向代理”之前,首先要介绍一下“正向代理”的概念。

1.什么是正向代理?

在NAT技术(Network Address Translation)出现之前,所有主机无法直接与外网相连,要想上网,需要连接到一台能够访问外网的Web服务器,再通过这台服务器访问外网。而这台Web服务器就叫做“正向代理服务器”。

现在的“翻墙”技术也是如何,我们把请求发给一台可以连接外面世界的Web服务器,由它转发我们的请求,再将结果返回给我们。这台Web服务器就是“正向代理服务器”。

综上所述:正向代理服务器是客户端和目的服务器之间的一个中介,客户端通过正向代理服务器访问客户端原本无法访问的目标服务器。

2.什么是反向代理?

客户端向一个服务器A提交请求后,服务器A偷偷地去服务器B上获取资源,并返回给客户端。客户端天真地以为数据是服务器A给他的。在这过程中,服务器A称为“反向代理服务器”,服务器B称为反向代理服务器的“后端服务器”。

3.“正向代理”与“反向代理”的区别?

两者最直观的区别是在用户的角度。“正向代理”是用户使用的技术。用户首先是知道自己要访问的目标服务器是谁,但由于某种原因无法直接访问该目标服务器,因此选择使用正向代理服务器帮忙转发请求。

而“反向代理”是服务器使用的技术。用户向服务器发送请求后,服务器在用户不知情的情况下去其他服务器上获取资源并返回给用户。

什么是反向代理服务器?

反向代理服务器用于存储静态数据和缓存数据,它处于Web服务器之前。当用户发起请求时,请求首先被反向代理服务器截获,若请求的是静态数据或缓存数据,则反向代理服务器直接将数据返回;若请求的是动态数据,且缓存中不存在,则反向代理服务器将请求转发给后端的Web服务器,在获取后端服务器的数据后再返回给用户。

反向代理服务器有何作用?

反向代理服务器能够分担后端服务器的压力。在请求数很高的情况下,即使服务器使用了缓存,但仍然无法应对巨大的并发数,因此需要反向代理服务器的帮忙。反向代理服务器收到请求后,如果请求的是缓存数据或静态数据,则直接返回给用户,而无需再劳驾后端服务器了,从而缓解后端服务器的压力。

如何使用反向代理缓存?

1.如何选择反向代理服务器?

反向代理服务器有多种选择,可以使用Nginx的反向代理模块,但它毕竟是Nginx的一个插件,功能不够全面。 Squid是一个缓存服务器,除提供反向代理外还拥有其他功能,但过于重量级,历史也比较悠久,性能不咋地。 Varnish是一款专门用于反向代理的服务器,相对于Squid较为轻量,由于使用内存缓存,因此性能较好,但也收到了内存的存储容量的限制。 究竟哪一个反向代理服务器适合你,可以参考: varnish / squid / nginx cache 有什么不同? 这里我们以Varnish为例。

2.搭建Varnish服务器

  1. 下载安装Varnish 首先你需要去Varnish官网下载并安装Varnish,这里不做详细介绍了。
  2. 配置Varnish的后端服务器的IP和端口号
backend default{
    .host = "127.0.0.1";
    .port = "80";
}
  1. 启动Varnish 在启动时,你需要指定如下参数:
    • Varnish对外的端口
    • Varnish命令行操作的端口
    • 缓存空间的大小 PS:Varnish会采用一种类似于Mysql Innodb的存储引擎来存储缓存数据。

3.自定义Varnish的缓存规则

Varnish采用VCL(Varnish Configuration Language)来让我们自定义缓存规则。

Varnish将反向代理的处理过程分为多个阶段,每个阶段都会触发对应的函数,我们可以在这些函数中配置具体的缓存处理策略。 下面对常用规则的配置进行介绍:

1.vcl_revc函数

sub vcl_revc{
    if(req.request!="GET" && 
        req.request!="POST" &&
        req.request!="PUT" &&
        req.request!="HEAD" &&
        req.request!="OPTIONS" &&
        req.request!="DELETE" &&
        req.request!="TRACE"){
            return(pipe);
    }

    if(req.request!="GET" && 
        req.request!="HEAD"){
            return(pass);
    }


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

    return (lookup);
}
  • pass:表示不检查缓存,直接将请求转发给后端服务器,从而触发vcl_pass函数;
  • lookup:表示从缓存中查找,若命中缓存则触发vcl_hit函数,若未命中缓存则触发vcl_miss函数;
  • req.request:表示HTTP请求的类型
  • req.http.Cookie:表示请求中是否携带Cookie;
  • client.ip:用户的IP
  • req.url:用户请求的URL
  • req.http.[header-key]:http请求头中的某个属性
  • obj.status:后端服务器返回的HTTP响应状态码
  • obj.response:后端服务器返回的HTTP响应头中的状态信息(状态码后面的文字说明)
  • obj-cacheable:表示是否可以缓存后端服务器返回的数据。当后端服务器返回的响应头状态码为200、203、300、301、404、410,并且包含Expires或Cache-Control标记时,Varnish就会根据过期时间将数据缓存起来。

2.vcl_fetch函数

sub vcl_fetch{
    if(!obj.cacheable){
        return(pass);
    }

    if(obj.http.set-Cookie){
        return(pass);
    }

    set obj.prefetch = -30s;
    return (deliver);
}
  • pass:代表将后端服务器发来的数据直接返回给浏览器,而不需要缓存
  • deliver:代表将后端服务器发来的数据写入缓存
  • if(!obj.cacheable){return(pass);}:表示当前内存不允许缓存的话直接返回给客户端;
  • if(obj.http.set-Cookie){return(pass);}:表示如果后端服务器返回的数据中设置了Cookie,那么Varnish也不需要缓存,直接将数据返回给客户端。

4.清除Varnish中的缓存

Varnish提供了两种清除缓存的方式:

  • 通过Varnish命令行
    varnishadm -T localhost:8011 purge.url /xxx.html
  • 通过HTTP远程清除缓存 通过Varnish的HTTP服务端口发送如下请求:
PURGE /xxx.html HTTP/1.0
Host:Varnish的地址

后端服务器能够使用HTTP方式删除Varnish上的指定的缓存。

5.监控Varnish中的缓存命中率

使用varnishstat命令即可查看当前Varnish的运行情况,下面是Varnish运行参数的说明:

  • Client requests recived: Varnish接收到的所有请求的个数。
  • Cache hits: 缓存命中的个数。
  • Cache misses: 缓存未命中的个数。
  • N expired objects: 过期缓存的个数。
  • N LRU moved objects: 被淘汰的缓存的个数。
  • Total header bytes: 当前缓存中所有数据的HTTP Header长度。
  • Total body bytes: 当前缓存中所有数据的HTTP body长度。

PS:Varnish还提供了可视化的监控界面。

分配多大的缓存空间较为合适?

首先,我们需要通过压力测试来估算网站的最大并发数。 然后观察反向代理服务器中缓存空间的使用率与命中率。 如果缓存空间长时间处于满载,并且缓存的命中率很低,并且后端服务器的实际并发数接近最大并发数,那么我们就需要考虑增加缓存的存储空间。增加缓存空间后,一方面能提高缓存命中率,一方面能减轻后端服务器的压力。

设置多长的缓存有效期较为合适?

若缓存有效期过长,虽然能够大大减轻后端服务器的压力,但数据的实时性将大大降低;若缓存有效期过短,那么虽然数据实时性大大提高,但后端服务器的压力也增加。

所以缓存有效期的确定需要根据实际的业务情况,如果你的网站对实时性要求很高,那么就需要设置较短的缓存有效期,如果对实时性要求不高,那么可以将缓存设置长一些,从而减轻后端服务器压力。

当然,如果你网站平实的并发数达不到服务器所能承受的最大并发数,那完全可以不用考虑缓存,用户每次请求都让后端服务器直接处理,一切都不用那么麻烦了。

ESI简介

如果有些页面中大部分地方都不需要实时更新,而局部对实时性要求较高,那么可以使用ESI技术,对页面不同的地方设置不同的缓存有效期。

将 后端服务器缓存 和 反向代理缓存一起使用

讲到这里,也许有的人要问,反向代理服务器实现了缓存的功能,那么后端服务器还需要缓存吗?答案是:当然需要! 原因主要有如下两点:

  1. 反向代理服务器有时会漏掉一些原本需要缓存的数据,后端服务器的缓存能避免用户请求这部分数据时消耗太多时间;
  2. 反向代理服务器的数据缓存是在用户第一次请求时进行的,而后端服务器的数据缓存是在服务器启动时完成的。因此,如果使用了后端服务器的缓存,当用户请求尚未被反向代理服务器缓存的数据时,后端服务器可以直接将这部分缓存数据返回给用户,从而节约了用户等待时间,也减少了后端服务器的开销。

反向代理服务器与后端服务器的网络环境搭建

由于反向代理服务器和后端服务器是通过TCP进行数据通信,因此为了降低他们之间的通信时延,需要将这两台服务器放在内部网络下,并通过交换机相连。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端技术探索

nginx 多进程架构详解

一、进程模型 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧。

561
来自专栏风中追风

分布式基础__HTTP 通信协议

https://www.zhihu.com/question/44323871/answer/347628315 这个地址是知乎上的一个问题,

34115
来自专栏Java学习123

IBM WebSphere MQ 系列(一)基础知识

2564
来自专栏java一日一条

web中缓存的几种方式

应用程序把动态文件生成的html文件缓存到文件服务器,以后用户请求动态文件,直接从文件服务器加载对应的静态缓存的html文件返回给用户,这里面主要节省了动态语言...

402
来自专栏大闲人柴毛毛

架构高性能网站秘笈(一)——了解衡量网站性能的指标

服务器如何发送数据? 服务器程序将需要发送的数据写入该程序的内存空间中; 服务器程序通过操作系统的接口向内核发出系统调用; 系统内核将用户态内存空间中的数据复制...

4369
来自专栏QQ会员技术团队的专栏

告知你不为人知的 UDP:连接性和负载均衡

说起网络 socket,大家自然会想到 TCP ,用的最多也是 TCP,UDP 在大家的印象中是作为 TCP 的补充而存在,是无连接、不可靠、无序、无流量控制的...

4.3K5
来自专栏Java进阶

HTTP 通信协议

3398
来自专栏aoho求索

认证鉴权与API权限控制在微服务架构中的设计与实现(四)

引言: 本文系《认证鉴权与API权限控制在微服务架构中的设计与实现》系列的完结篇,前面三篇已经将认证鉴权与API权限控制的流程和主要细节讲解完。本文比较长,对这...

3968
来自专栏xcywt

<HTTP协议详解>由浅入深看HTTP

1.支持客户/服务器模式。 2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务...

894
来自专栏mukekeheart的iOS之旅

浅谈Session与Cookie的区别与联系

1255

扫描关注云+社区