深入探讨Varnish缓存命中率
发布日期:2021-06-30 19:23:20 浏览次数:3 分类:技术文章

本文共 9643 字,大约阅读时间需要 32 分钟。

 

也许你还在为刚才动态内容获得7336.76 reqs/s的吞吐率感到振奋,等等,理想和现实是有差距的,你要忍受现实的残酷,别忘了,我们压力测试中的动态内容都处于全缓存情况下,也就是每次请求都命中缓存,这在现实中往往是不可能的。

首先,缓存区空间大小是有限的,而我们的站点可能有大量的内容需要被缓存,而不像前边压力测试时只有一个内容。一旦缓存区被装满,那么缓存管理器便会淘汰一些它认为不再需要的缓存内容,比如通过LRU(最近最少使用算法)将使用频率较低的缓存内容淘汰出去,但是,这里判断“不常使用”的标准是不严格的,也许被淘汰的内容就是你将要访问的下一个内容,这便影响了它的命中率。
其次,缓存的过期时间也影响到它的命中率,假如有效期很短,为10秒,那么最少10秒便会有一次无法命中。
还有,有些内容可能根本没有被代理服务器缓存,比如这些内容包含了set-cookie等不可缓存的HTTP头信息,导致反向代理不会缓存它们,并且在浏览器请求它们的时候也不会去缓存区查找。这是影响命中率的一个重要因素,但往往被我们所忽略。
幸运的是,这些问题我们都可以轻松的解决,前提是,我们需要了解反向代理缓存的实时工作状态,比如Varnish便提供了一个命令行的状态监控程序varnishstat,我们打开它,便看到了当前时刻的状态,如下:

client_conn           9908723        94.05 Client connections acceptedclient_drop                 0         0.00 Connection dropped, no sess/wrkclient_req           16433490       155.99 Client requests receivedcache_hit             8751732        83.07 Cache hitscache_hitpass           42592         0.40 Cache hits for passcache_miss            7573389        71.89 Cache missesbackend_conn          3889845        36.92 Backend conn. successbackend_unhealthy          220         0.00 Backend conn. not attemptedbackend_busy                0         0.00 Backend conn. too manybackend_fail             4536         0.04 Backend conn. failuresbackend_reuse         3780212        35.88 Backend conn. reusesbackend_toolate       3866687        36.70 Backend conn. was closedbackend_recycle       7646677        72.58 Backend conn. recyclesbackend_unused              0         0.00 Backend conn. unusedfetch_head                 57         0.00 Fetch headfetch_length           155097         1.47 Fetch with Lengthfetch_chunked         7508522        71.27 Fetch chunkedfetch_eof                   0         0.00 Fetch EOFfetch_bad                   0         0.00 Fetch had bad headersfetch_close              3982         0.04 Fetch wanted closefetch_oldhttp               0         0.00 Fetch pre HTTP/1.1 closedfetch_zero                  0         0.00 Fetch zero lenfetch_failed                0         0.00 Fetch failedn_sess_mem               1033          .   N struct sess_memn_sess                    633          .   N struct sessn_object              1016443          .   N struct objectn_vampireobject             0          .   N unresurrected objectsn_objectcore          1017564          .   N struct objectcoren_objecthead           982903          .   N struct objectheadn_smf                 2647421          .   N struct smfn_smf_frag             622470          .   N small free smfn_smf_large                 3          .   N large free smfn_vbe_conn                 12          .   N struct vbe_connn_wrk                    8000          .   N worker threadsn_wrk_create             8000         0.08 N worker threads createdn_wrk_failed                0         0.00 N worker threads not createdn_wrk_max               11021         0.10 N worker threads limitedn_wrk_queue                 0         0.00 N queued work requestsn_wrk_overflow           2441         0.02 N overflowed work requestsn_wrk_drop                  0         0.00 N dropped work requestsn_backend                   4          .   N backendsn_expired             6344546          .   N expired objectsn_lru_nuked            183957          .   N LRU nuked objectsn_lru_saved                 0          .   N LRU saved objectsn_lru_moved           3692170          .   N LRU moved objectsn_deathrow                  0          .   N objects on deathrowlosthdr                    84         0.00 HTTP header overflowsn_objsendfile               0         0.00 Objects sent with sendfilen_objwrite           15466812       146.81 Objects sent with writen_objoverflow               0         0.00 Objects overflowing workspaces_sess                9906155        94.03 Total Sessionss_req                16433490       155.99 Total Requestss_pipe                     37         0.00 Total pipes_pass                 108252         1.03 Total passs_fetch               7667658        72.78 Total fetchs_hdrbytes         7187255662     68221.35 Total header bytess_bodybytes      111592032839   1059230.32 Total body bytessess_closed           1905544        18.09 Session Closedsess_pipeline               0         0.00 Session Pipelinesess_readahead              0         0.00 Session Read Aheadsess_linger          15277717       145.02 Session Lingersess_herd            13547370       128.59 Session herdshm_records        1028855796      9765.89 SHM recordsshm_writes           77957008       739.97 SHM writesshm_flushes            131005         1.24 SHM flushes due to overflowshm_cont               144281         1.37 SHM MTX contentionshm_cycles                427         0.00 SHM cycles through buffersm_nreq              15306717       145.29 allocator requestssm_nobj               2024948          .   outstanding allocationssm_balloc         13595295744          .   bytes allocatedsm_bfree          40091795456          .   bytes freesma_nreq                    0         0.00 SMA allocator requestssma_nobj                    0          .   SMA outstanding allocationssma_nbytes                  0          .   SMA outstanding bytessma_balloc                  0          .   SMA bytes allocatedsma_bfree                   0          .   SMA bytes freesms_nreq                14062         0.13 SMS allocator requestssms_nobj                    0          .   SMS outstanding allocationssms_nbytes                487          .   SMS outstanding bytessms_balloc            6844837          .   SMS bytes allocatedsms_bfree             6846298          .   SMS bytes freedbackend_req           7668789        72.79 Backend requests maden_vcl                       1         0.00 N vcl totaln_vcl_avail                 1         0.00 N vcl availablen_vcl_discard               0         0.00 N vcl discardedn_purge                740577          .   N total active purgesn_purge_add            905392         8.59 N new purges addedn_purge_retire         164815         1.56 N old purges deletedn_purge_obj_test     13397373       127.17 N objects testedn_purge_re_test  131875330367   1251759.15 N regexps tested againstn_purge_dups           240655         2.28 N duplicate purges removedhcb_nolock                  0         0.00 HCB Lookups without lockhcb_lock                    0         0.00 HCB Lookups with lockhcb_insert                  0         0.00 HCB Insertsesi_parse                   0         0.00 Objects ESI parsed (unlock)esi_errors                  0         0.00 ESI parse errors (unlock)accept_fail              2553         0.02 Accept failuresclient_drop_late            0         0.00 Connection dropped lateuptime                 105352         1.00 Client uptime

看起来很强大,的确,它帮我们获得了很多重要的信息,包括了三个重要的统计项:

N struct object

当前被cache的条目

Client requests received

代表到目前为止,浏览器向反向代理服务器发送的HTTP请求累积次数,由于可能使用长连接,所以它可能会大于上边的Client connections accepted。

Cache hits

代表在这些请求中,反向代理服务器在缓存区中查找并且命中缓存的次数。

Cache misses

代表在这些请求中,反向代理服务器在缓存区中查找但是没有命中缓存的次数。

N expired objects

代表过期的缓存内容个数

N LRU nuked objects

由于cache空间满而不得不扔掉的cache条目,如果这个数字是0,就没必要增加cache的大小了。

N LRU moved objects

代表被淘汰的缓存内容个数

Total header bytes

代表缓存区中所有缓存内容的HTTP头信息长度

Total body bytes

代表缓存区中所有缓存内容的正文长度

通过以上这些统计项,我们还可以知道更多,比如Cache hits和Cache misses的总和代表了反向代理服务器在缓存区中查找内容的总次数;而用Client requests received减去这个总次数,便大概等于没有查找缓存的请求数;Total body bytes和Total body bytes的总和则代表了缓存区当前的空间使用量。
了解了这些后,我们回头看前边的三个问题,都很容易分析和解决。
对于缓存区空间大小的问题,我们可以通过监视它的使用量以及缓存淘汰个数,在必要的时候分配更多的缓存区空间,但是这可能需要重新启动反向代理服务器。当然,我们应该首先根据站点的规模,来估算出大概的缓存区空间,并且分配出大约为它5倍以上的缓存区空间,以适应一段时期内的内容数量增长。
其次,是缓存有效期取值的问题,但这本身不是一个问题,它取决于后端Web服务器的承受能力,以及你对站点内容实时性的要求,我们在前边介绍动态内容缓存的章节中曾经探讨过缓存有效期的取值,实质上是一个寻找“过”与“不及”之间平衡的长期过程,但在动态程序实现的内容缓存机制中,我们还可以通过主动删除缓存的方法来实现缓存到期之前的更新,而基于HTTP协议的反向代理缓存机制则不容易做到这一点,后端的动态程序无法主动删除某个缓存内容,除非我们清空反向代理服务器上的缓存区。
在寻找平衡的过程中,有时候实时性需求可能要向缓存有效期适当让步,当我们的站点面临较大的压力时,我们不得不暂时以牺牲实时性作为代价,适当的延长缓存有效期,直到我们有了成熟的性能扩展方案。
在初步评估缓存有效期的时候,我们可以通过一些量化的计算来得出理论数值,举个例子,假如我们的站点有60000个动态内容处于频繁访问的状态,我们通过Cache-Control将它们在反向代理服务器上的缓存有效期都设置为60秒,这样一样来,后端服务器将必须承受最多每秒处理1000个动态内容的工作量,如果这些动态内容都进行完整的计算,比如访问数据库,那么显然后端服务器是无法承受的,这时候我们可以将缓存有效期延长到300秒,即5分钟,这使得后端服务器只需要每秒处理200个动态内容,大大减少了工作量。
那么,如果从缓存命中率的角度来分析缓存有效期取值的时候,有一点需要明白,当我们看到缓存的命中率非常低时,有时并不代表我们需要马上延长缓存有效期,这时候还要观察当前的站点实际吞吐率,举个极端的例子,假如你发现你的站点1个小时内只有1次访问,而缓存有效期为半个小时,那缓存命中率必然会非常低,但即便是每次缓存都不命中,也不会对后端带来什么压力,实际上如果你的站点只有一台Web服务器,并且站点的实际吞吐率远远低于它的处理能力时,完全没有必要使用反向代理服务器。
最后关于内容没有被缓存的问题,我们也可以在Varnish的状态监视中找到线索,比如有一个用Varnish加速第三方应用wordpress的例子,得到的Varnish状态如下:

4+10:37:44my.server.comHitrate ratio: 1 1 1Hitrate avg: 0.0364 0.0364 0.03642324 0.00 0.01 Client connections accepted6191 0.00 0.02 Client requests received12 0.00 0.00 Cache hits7 0.00 0.00 Cache hits for pass318 0.00 0.00 Cache misses6179 0.00 0.02 Backend connections success0 0.00 0.00 Backend connections notattempted0 0.00 0.00 Backend connections too many0 0.00 0.00 Backend connections failures4057 0.00 0.01 Backend connections reuses6151 0.00 0.02 Backend connections recycles...

我们看到,Varnish一共处理了来自浏览器的6191个请求,其中命中缓存的有12个,真是太少了,而没有命中缓存的有318个,奇怪,剩下的那么多请求根本就没有去缓存区检查,也就是说,Varnish认为那些内容不能被缓存。不能被缓存总是有原因的,你需要根据反向代理缓存的规则,来进一步的检查。而我们这个例子中,都是cookies惹得祸,因为在wordpress中由于我们会安装一些各种各样的插件,有些插件会使得wordpress的每个页面都带有写入cookies的set-cookie标记,而我们前边在vcl_fetch函数中禁止了这类内容的缓存,问题就在这里了,我们希望将这些多余的cookie关闭掉,但是,wordpress自身的登录和管理页面是需要cookies才可以正常工作的,所以我们还需要让反向代理不缓存这些页面,我们使用以下VCL配置:

sub vcl_recv{if (!(req.url ~ "wp-(login|admin)")){unset req.http.cookie;}}sub vcl_fetch{if (!(req.url ~ "wp-(login|admin)")){unset obj.http.set-cookie;}}

可以看到,除了wordpress自身的登录和管理页面以外,我们将其它内容的HTTP头信息中有关cookie的标记全部都清除掉,这使得Varnish可以将大部分内容缓存起来,提高缓存命中率,同时不影响我们登录和管理wordpress。

这个例子给了我们一些启示,对于我们自己的站点,如果从长远考虑,那么在规划的时候就要费点心思,我们可以根据内容是否可以缓存在反向代理服务器上,将它们置于不同的主机,这样便可以在必要的时候将可以缓存的内容快速与反向代理服务器对接,获得较好的加速效果。

转载地址:https://linuxstyle.blog.csdn.net/article/details/6584793 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Linux下文件如果没有权限不能被Apache访问
下一篇:设置Sysctl.conf用以提高Linux的性能(最完整的sysctl.conf优化方案)

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月07日 08时10分36秒