Varnish开源高性能反代和缓存服务器

官方网站:Varnish HTTP Cache — Varnish HTTP Cachehttp://varnish-cache.org/

#数据流向: 首先客户端发送的数据 ----->>>>>>>>>>>>>>>>>>>>CDN(内容分发网络) 【主要的作用可以是本地缓存与反向代理:举例:淘宝总部在杭州,在新疆与杭州的访问的速度就不一样,用户体验差,解决问题方法:在新疆也搭建一个与杭州的相同的服务器,所以数据包可以不出省,但是需要考虑同步问题,这涉及到CDN的细节问题】 --------->>>>>>>>>>>>>>>>>>>>>>>lvs/F5 四层分流 【缓存没有时,到传输层,主要用于分流。举例:当访问流量大时,需要多加服务器,但是用户不知道新增的服务器,故增加一个==入口==,至于分到那一台服务器,这就是lvs】 --------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>HA+lvs 【当接口崩的时候,可以多做几台备用服务器,对于用户毫无影响】 --------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>nginx/proxy 七层分流 【按照业务分流】 ---------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>web(apache/nginx) 【apche稳定,nginx静态访问】 ----------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>app(php/jsp)动态网页 ----------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>DB(mysql/redis app中需要保存一些数据) ----------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>各种组件(监控zabbix docker k8s hadoop elk[查日志] OpenStack cluster) 

当前计算机系统的内存除了主存外,还包括CPU的L1级缓存、L2级缓存,甚至还包括L3级缓存。硬盘也有缓存,而Squid的架构导致其无法做到最佳存取,但操作系统可以实现这部分功能,所以这部分工作应该交给操作系统来处理,这就是Varnish Cache设计架构。挪威最大的在线报纸Verdens Gang(vg.no)使用了3台Varnish服务器代替了原来的12台Squid服务器,而且性能比以前更好,这是Varnish最成功的应用案例之一。

当把Varnish部署上之后,web请求的处理过程会有一些变化。客户端的请求将首先被Varnish接受。Varnish将分析接收的请求,并将其转发到后端的web服务器上。后端的web服务器对请求进行常规的处理,并将依次将处理结果返回给Varnish。

但Varnish的功能并非仅限于此。Varnish的核心功能是将后端web服务器返回的结果缓存起来,如果发现后续有相同的请求,Varnish将不会将这个请求转发到web服务器,而是返回缓存中的结果。这将有效的降低web服务器的负载,提升响应速度,并且每秒可以响应更多的请求。Varnish速度很快的另一个主要原因是其缓存全部都是放在内存里的,这比放在磁盘上要快的多。诸如此类的优化措施使得Varnish的相应速度超乎想象。但考虑到实际的系统中内存一般是有限的,所以需要手工配置一下缓存的空间限额,同时避免缓存重复的内容。

处理缓存的顺序:接受到请求 –- 分析请求(分析你的URL,分析你的首部) — hash计算 — 查找缓存 — 新鲜度检测 — 访问源 — 缓存 – 建立响应报文 – 响应并记录日志。

监听端口6081,管理进程management,子进程child/cache。

Varnish特点与Squid的对比

Varnish特点:

基于内存缓存,重启后数据将消失。
利用虚拟内存方式,I/O性能好。
支持设置0~60秒内的精确缓存时间。
VCL(全称varnish config language,这是Varnish自己领域的特定语言)配置管理比较灵活。
32位机器上缓存文件大小为最大2G。
具有强大的管理功能,例如top,stat,admin,list等。
状态机设计巧妙,结构清晰。
利用二叉堆管理缓存文件,达到积极删除目的。

Varnish与Squid的对比:

相同点:

都是一个反向代理服务器;
都是开源软件;

Varnish相较于Squid的优点:

Varnish的稳定性很高,两者在完成相同负荷的工作时,Squid服务器发生故障的几率要高于Varnish,因为使用Squid要经常重启;
Varnish访问速度更快,Varnish采用了“Visual Page Cache”技术,所有缓存数据都直接从内存读取,而Squid是从硬盘读取,因此Varnish在访问速度方面会更快;
Varnish可以支持更多的并发连接,因为Varnish的TCP连接释放要比Squid快,所以在高并发连接情况下可以支持更多TCP连接;
Varnish可以通过管理端口,使用正则表达式批量的清除部分缓存,而Squid是做不到的;
Squid属于是单进程使用单核CPU,但Varnish是通过fork形式打开多进程来做处理,所以是合理的使用所有核来处理相应的请求;

Varnish相较于Squid的缺点:

Varnish在高并发状态下CPU、I/O和内存等资源开销都高于Squid;
Varnish进程一旦Hang(挂起)、Crash(崩溃)或者重启,缓存数据都会从内存中完全释放,此时所有请求都会发送到后端服务器,在高并发情况下,会给后端服务器造成很大压力;
在Varnish使用中如果单个url的请求通过HA/F5(负载均衡)每次请求不同的varnish服务器中,被请求varnish服务器都会被穿透到后端,而且同样的请求会在多台服务器上缓存,也会造成Varnish的缓存的资源浪费,也会造成性能下降。

工作流程图:

Varnish开源高性能反代和缓存服务器插图1

结构特点:

Varnish把数据存放在服务器的内存中,这种模式的效率是最高的,不过重启后数据会消失,官方透露3.0版本可以解决这个问题。Varnish可以设置0~60秒的精确缓存时间,不过32位的机器支持的缓存文件最大为2 GB。Varnish采用VCL的配置,而且具有强大的管理功能,如top、stat、admin、lis,所以管理方式比较灵活。Varnish的状态机设计不仅巧妙,结构也很清晰,利用二叉堆管理缓存文件,即可达到随时删除的目的。

与传统的Squid 相比,Varnish具有性能更高、速度更快、管理更加方便等诸多优点:

Varnish采用了“Visual Page Cache”技术,所有缓存的数据都直接从内存读取,而Squid从硬盘读取缓存的数据,它避免了Squid频繁在内存、磁盘中交换文件,性能要比Squid高。

Varnish稳定性比Squid高,宕机率很低。

通过Varnish管理端口,可以使用正则表达式快速、批量地清除部分缓存,这一点是Squid不能具备的。

Varnish可以支持更多的并发连接。因为Varnish的TCP连接与释放比Squid快,所以在高并发连接情况下可以支持更多的TCP连接。

不足:Varnish在高并发状态下,CPU、I/O和内存等资源的开销高于Squid。Varnish的进程一旦挂起、崩溃或者重启,缓存的数据都会从内存中释放出来。此时的所有请求都会被发送到后端应用服务器上,在高并发的情况下,就会给后端服务器造成很大压力。

工作原理:

Varnish 与一般服务器软件类似,分为master 进程和child 进程。master进程读入存储配置文件,调用合适的存储类型,然后创建/ 读入相应大小的缓存文件,接着master 初始化管理该存储空间的结构体,然后fork 并监控child 进程。child进程在主线程的初始化的过程中,将前面打开的存储文件整个mmap 到内存中,此时创建并初始化空闲结构体,挂到存储管理结构体,以待分配。child进程分配若干线程进行工作,主要包括一些管理线程和很多worker 线程。

接着,开始真正的工作,varnish的某个负责接收新HTTP 连接线程开始等待用户,如果有新的HTTP连接过来,它总负责接收,然后唤醒某个等待中的线程,并把具体的处理过程交给它。Worker线程读入HTTP 请求的URI,查找已有的object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。

分配缓存的过程是这样的:它根据所读到object 的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个object的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据LRU 机制,把最旧的object 释放掉。

释放缓存的过程是这样的:有一个超时线程,检测缓存中所有object 的生存期,如果超初设定的TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。

整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的object 都考虑是在内存中,如果系统内存不足,系统会自动将其换到swap 空间,而不需要varnish 程序去控制。

CentOS 7 下安装搭建过程: yum install -y varnish systemctl start varnish systemctl enable varnish #设置监听端口,默认6081 vim /etc/varnish/varnish.params VARNISH_LISTEN_PORT=6081 #设置后端服务器 vim /etc/varnish/default.vcl backend default { .host = "192.168.80.100"; .port = "80"; .probe = { .timeout = 5s; .interval = 2s; .window = 10; .threshold = 8; } } #vcl配置示例: # # This is an example VCL file for Varnish. # # It does not do anything by default, delegating control to the # builtin VCL. The builtin VCL is called when there is no explicit # return statement. # # See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/ # and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples. # Marker to tell the VCL compiler that this VCL has been adapted to the # new 4.0 format. vcl 4.0; # Default backend definition. Set this to point to your content server. backend default { .host = "127.0.0.1"; .port = "80"; } sub vcl_recv { # Happens before we check if we have this in cache already. # # Typically you clean up the request here, removing cookies you don't need, # rewriting the request, etc. if (req.url ~ "\.(php|asp|aspx|jsp|do|ashx|shtml)($|\?)") { return (pass); } if (req.url ~ "\.(css|js|html|htm|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)($|\?)") { unset req.http.cookie; return (hash); } 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.http.Cache-Control ~ "(?i)no-cache") { if (!(req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) { return (purge); } } if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "PATCH" && req.method != "DELETE") { return (pipe); } if (req.method != "GET" && req.method != "HEAD") { return (pass); } if (req.http.Authorization) { return (pass); } if (req.http.Accept-Encoding) { if (req.url ~ "\.(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$") { unset req.http.Accept-Encoding; } elseif (req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elseif (req.http.Accept-Encoding ~ "deflate") { set req.http.Accept-Encoding = "deflate"; } else { unset req.http.Accept-Encoding; } } if (req.http.Upgrade ~ "(?i)websocket") { return (pipe); } if (req.http.x-pipe && req.restarts > 0) { unset req.http.x-pipe; return (pipe); } return (hash); } sub vcl_pipe { if (req.http.upgrade) { set bereq.http.upgrade = req.http.upgrade; } return (pipe); } sub vcl_pass { if (req.method == "PURGE") { return (synth(502, "PURGE on a passed object.")); } } sub vcl_hash { hash_data(req.url); if (req.http.host) { hash_data(req.http.host); } else { hash_data(server.ip); } if (req.http.Cookie) { hash_data(req.http.Cookie); } if (req.http.Accept-Encoding ~ "gzip") { hash_data("gzip"); } elseif (req.http.Accept-Encoding ~ "deflate") { hash_data("deflate"); } } sub vcl_hit { if (req.method == "PURGE") { return (synth(200, "Purged.")); } if (obj.ttl >= 0s) { return (deliver); } return (deliver); } sub vcl_miss { if (req.method == "PURGE") { return (synth(404, "Purged.")); } return (fetch); } sub vcl_backend_response { # Happens after we have read the response headers from the backend. # # Here you clean the response headers, removing silly Set-Cookie headers # and other mistakes your backend does. } sub vcl_purge { if (req.method != "PURGE") { set req.http.X-Purge = "Yes"; return (restart); } } #设置检查是否命中X-Cache sub vcl_deliver { if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; } else { set resp.http.X-Cache = "MISS"; } unset resp.http.X-Powered-By; unset resp.http.Server; unset resp.http.Via; unset resp.http.X-Varnish; unset resp.http.Age; }

说明:

#http请求处理过程
#1,receive请求入口状态,根据vcl判断pass还是lookup本地查询
#lookup,在hash表中查找数据,若找到则进入hit状态,否则进入fetch状态
#pass,选择后台,进入fetch状态
#fetch,对请求进行后端的获取,发送请求,获得数据,并进行本地存储
#deliver,将数据发送给客户端,进入done
#done,处理结束

.扩展 1)为什么要使用缓存: 访问过的数据会再次被访问到,热数据多次访问。 一个数据被访问过会后,离他最近的或者较近的客户端再次访问。 2)既然要缓存, 需要读取的高速,最好的方法,就是全部放到内存。 常见的内存数据库,memcached,redis,HANA。 但是对于页面,全放放到内存,太不现实,内存+高速缓存盘的方式来存储缓存。 Key-value,key存放于内存,value存放磁盘。 3)一种数据形式:key value Key:对访问路径,URL,特定的特征,进行hash计算得出的结果,这种key存放于内存中。 Value:页体,我们用户真正得到的内容,一般存放在高速硬盘。 4)凡是与缓存缓存相关的,离不开两体:内存,高速硬盘。 5)常见的术语: 命中:能从缓存取出数据,如果是一台web站点,那么你的缓存服务器将是一台最前端服务器。 命中率:命中次数/(命中次数+非命中次数)。 热数据:经常被访问的数据。 内存缓存空间,磁盘缓存空间。 清理:定期清理,LRU(不常用的,最老的一类数据将其删除),定期更新(purge)。 缓存对象:用户信息,cookies,交易信息,页面内存,统统理解为object。

验证:

使用谷歌浏览器查看:

Varnish开源高性能反代和缓存服务器插图2

参考资料:

Linux下Varnish缓存的配置优化_服务器应用_Linux公社-Linux系统门户网站

原文链接:https://blog.csdn.net/qq_34777982/article/details/123462316

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享