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

什么是反向代理?

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

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 条评论
登录 后参与评论

相关文章

来自专栏aCloudDeveloper

python网络编程初级

网络编程的专利权应该属于Unix,各个平台(如windows、Linux等)、各门语言(C、C++、Python、Java等)所实现的符合自身特性的语法都大同小...

2065
来自专栏desperate633

深入理解HTTP1.0和HTTP1.1的区别

HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客...

591
来自专栏互联网大杂烩

TCP/IP协议

TCP/IP协议并不完全符合OSI的七层参考模型。传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使...

762
来自专栏技术博文

HTTP 长连接和短连接

1. HTTP协议与TCP/IP协议的关系 HTTP的长连接和短连接本质上是TCP长连接和短连接。HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用I...

3088
来自专栏我和PYTHON有个约会

30.1. 企业级开发进阶2.1:TCP编程

农历五月初二 宜 抽烟 抽烟有利于提神,增加思维敏捷 晚上加班 晚上是程序员精神最好的时候

681
来自专栏Golang语言社区

Web负载均衡

序: 对Web站点扩展一开始不宜过早,除非是基于高可用性和就近部署的考虑。但对于架构师而言,在架构设计之初就要有扩展的计划,关键是要清楚何时进行扩展。这...

3287
来自专栏高性能服务器开发

从抓包的角度分析connect()函数的连接过程

这篇文章主要是从tcp连接建立的角度来分析客户端程序如何利用connect函数和服务端程序建立tcp连接的,了解connect函数在建立连接的过程中底层协议栈做...

771
来自专栏吴伟祥

计算机网络基础知识总结 转

计算机网络学习的核心内容就是网络协议的学习。网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。因为不同用户的数据终端可能采取的字符集是不...

431
来自专栏Jackson0714

Http协议原理解析第一篇

3588
来自专栏程序员与猫

从输入url到页面返回到底发生了什么

1. 前言 Google应该是开发者平日里用得最多的网站之一,今早笔者在浏览器地址栏里键入www.google.com的时候,突然想了解下这背后的网络通信过程究...

2058

扫码关注云+社区