缓存服务器设计与实现(五)

上次讲到lru与缓存重建,这次主要讲一下关于过期处理的一些主要问题。在讨论这个问题之前,有个相关的问题需要大家有所了解。就是对于一个缓存如期只来说,什么东西应该缓存,什么不应该缓存。这是一个比较复杂的问题,涉及到http协议的诸多细节。这里赵永明大哥写了一篇文章,讲得很详细,虽然是以ATS为背景讲的,但是思路是想通的,大家可以点击[这里](https://blog.zymlinux.net/index.php/archives/1090)去看一下,文章名字很骚气叫*“to
cache or not to cache,一直是个大问题”*。

在缓存服务器里,分hit和miss两种行为。前面的文章已经讲过了,服务器本地有缓存叫hit处理(*也会因为if-modified-since转成miss处理,这个后面讲*),无缓存是miss处理。过期处理自然发生的本地有相应文件的基础上,miss情况下根本没有校验文件过期与否的动作可言。这里我以我们cache服务器为例讲一下基本的过期处理流程,当然开源的squid,ats之类的在这块也是大同小异。

一个文件缓存与否,包括缓存多长时间,通常取决于取源返回的响应中关于缓存相关的一些头部,例如:Expires,Cache-Control,Pragma, Last-Modified,Etag, Age,Vary等。这些头的解释,大家可以去翻看协议,不想翻协议的,可以从[这里](http://www.cnblogs.com/_franky/archive/2011/11/23/2260109.html)找到一个总结,这里就不浪费口舌了。

但是有一种情况必须考虑,对于CDN来说,他们服务的客户运营水平参差不齐,很多都没有相关的响应头来告诉CDN厂商,他们想缓存多长时间。通常在这种情况下,CDN厂商有这样一些规则,要么缓存指定的一段时间,这个时间CDN厂商自己控制。要么针对不同的文件后缀,对缓存时间做更细致化的控制,这种情况就不再讨论了。我们接下来重点讨论有正规缓存头部的情况。

当请求到来,cache服务器在本地找到了相应的文件,这里所谓的“找到的文件”多数都是所谓的文件在内存中的索引结构,因为这个结构中通常包括对应磁盘文件的所有信息。为了方便讨论,我们这里暂且把这个索引结构叫做store。

首先store结构中有一个成员,我们暂且叫cache_time,它记录的是缓存服务器在最开始存储这个文件时的时间,通俗点说就是取源回来开始缓存这个文件,就把当前时间记录在cache_time这个成员里。也可以说这个时间认为是缓存开始在本地构建这个文件的时间。

在store结构中通常有一个成员来保存源响应头中Date字段对应的时间戳,我们暂且将这个成员叫做backend_date,这个头一般是后端服务器在发送响应时拿它的当前时间戳构建的。

为了方便讨论,我们把缓存服务器的当前时间称为current_time。

- 首先处理Cache-Control的相关头部。如果cache_time+ max-age < current_time,说明这个文件过期了。这里的max-age是Cache-Control中的一个字段。否则当前的验证说明未过期,需要进一步检查其他过期信息。

- 如果存在源响应带有Expires头,那么比较expires - backend_date与current_time - cache_time的大小。首先前者表示这个文件在源服务器还有多长时间过期,后者表示这个文件在本机创建,当现在已经过去了多长时间。如果前者大于后者,意味文件可以继续使用,未过期。当然这是基于第一点中max-age检查,未过期的基础之上的。如果前者小于后者呢?我们就认为是过期了,但是会出现这种情况吗?后者的时间差来自于本地服务器,我们假定是准确的,但是前者的时间来自于其他后端服务器,不一定准确,就可能出现这种情况。出现了这种情况,只能当做过期处理。我们也碰到过自己的机器时间不准了导致文件异常过期的bug。所以缓存服务器通常在启动时要确认机器时间是否准确,这点很重要。

在以上这里点检查通过之后,未标记为过期的,会进到后续的hit处理流程。过期的就需要取源。所以取源有两种,第一种是本地没有缓存该文件,另一种是文件已经缓存过,但是现在过期了。过期回源是,涉及到回源验证的问题。什么是回源验证?当一个文件过期了,你回源重新取的时候,可能这个文件在源服务器上并没有改动过,那么这时缓存服务器再取一遍是很傻,也是浪费带宽,降低性能的事情。这个时候,在store结构中有个成员往往保存了一个时间戳,我们暂且叫做mod_time,这个时间戳来自于最开始构建文件时,源给的响应中的Last-Modified头,这个头中的时间告诉了我们,在我们取源获取这个文件时,该文件在源服务器最后一次修改的时间。那么我们在回源验证时,将这个mod_time放到我们取源构建的请求头的If-Modified-Since中,源收到这个头之后,就会去查看文件在这个时间以后,有没有被修改过,如果修改过,那么源通过回应304响应,告知下游文件未发送变化,文件可以重用。否则,就通过200响应,发送最新文件。

一般的情况,缓存服务器都会把响应头跟响应体保存在一个文件中。接下来作为hit处理的后续流程,往往需要先去读取保存文件中的响应头,其中我们需要关心的是Last-Modified头。因为客户端可能携带着If-Modified-Since头,我们需要对比两者是否相等,如果相等,那么我们认为文件在客户端询问的时候之后没有改变过,我们给他304响应。这里有两个问题:

1. 为什么不把Last-Modified头放在store结构中,这样我们就不需要去读文件来获取这个头了。

> 因为对于缓存服务器一般的webserver,它给出的响应必须忠于源给出的响应,而很少有权利自己打包响应头,除非本机发生像5xx等这类情况,所以既然一定要读文件,就没有必要单独拿出来了。其次store结构作为每个文件的索引,会占用大量的内存。所以减少哪怕一个成员,在大量文件存储时,也能节省不少空间。

2. 如果客户端的If-Modified-Since跟我们的Last-Modified不相等,而是大于或者小于,该怎么处理?

> 如果前者小于后者,毫无疑问应该回应200,因为我们的最后修改时间比客户端问的时间要新。如果大于呢?我们是否应该去回源验证呢?这种情况我们之间也直接使用本地文件响应200处理。很多人认为这样处理不太合理,毕竟你作为缓存代理,无法知道在*“未来”*的时间点上,源有没有改动过文件。但是如果你去做回源验证,别人可能因此攻击你,每次都发带有If-Modified-Since将来很长时间的一个时间点,让你的缓存产生回源,极大的消耗你的性能,因为作为cache,减少回源是最核心的功能。CDN厂商之间的相互攻击早已不是什么新鲜事,我们都是交过学费的

时间: 2024-10-05 12:48:42

缓存服务器设计与实现(五)的相关文章

缓存服务器设计与实现(番外篇)

这个系列又更新了. 今天谈一个问题,目前cache软件在业界的使用现状.cache系统其实最大的使用场景,还是主要集中在CDN厂商里. 大概在2010年之前,各大CDN厂商基本清一色的使用squid.那时候的squid是绝对的主力. squid的作为cache领域的鼻祖,正是由于历史的久远,很多近10年左右流行起来的很多系统特性,它本身并不支持.比如sendfile,splice和多核等方面的支持,由于这些特性属于核心架构方面的功能,后期如果想引进的话,需要对squid的核心做大量的修改.对于C

缓存服务器varnish概念篇

一.Varnish 简介 Varnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang 使用3台Varnish代替了原来的12台Squid,性能比以前更好. Varnish 的作者Poul-Henning Kamp是FreeBSD的内核开发者之一,他认为现在的计算机比起1975年已经复杂许多.在1975年时,储存媒介只有两种:内存与硬盘.但现在计算机系统的内存除了主存外,还包括了CPU内的L1.L2,甚至有L3快取.硬盘上也有自己的快取装置,因此Squid Cac

memached分布式内存缓存服务器

一:memached简介 在许多高并发的应用中,把业务数据保持久化 ( 保存到数据库,磁盘文件或其它 ) 后,应用从持久化设备中读取数据并在浏览器中显示,随用户量,数据量增大,访问的集中,会出现持久化设备负担过重(典型的就是数据库),影响应用响应速度,应用延迟严重等重大问题.典型的应用就是 WEB 应用中的高并发网站. 这时候应用就需要一种缓存机制来提高并发读取速度的性能 , memcached 能在大中型系统中提供优秀的缓存服务. memcached 是高性能的分布式内存缓存服务器.一般的使用

memcached缓存服务器介绍及其安装过程

Memcache是什么? memcached是以LiveJournal旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件.现在 已成为mixi.hatena.Facebook.Vox.LiveJournal等众多服务中提高Web应用扩展性的重要因素. Memcached是一款开源.高性能.分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对Database的访问来加速web应用程序.许多Web应用都将数据保存到RDBMS中,应用服

分布式系统开发常见问题-1. session的复制与共享 2. 分布式缓存的设计

1. session的复制与共享 在web应用中,为了应对大规模访问,必须实现应用的集群部署.要实现集群部署主要需要实现session共享机制,使得多台应用服务器之间会话统一, tomcat等多数主流web服务器都采用了session复制以及实现session的共享. 但问题还是很明显的: 在节点持续增多的情况下,session复制带来的性能损失会快速增加.特别是当session中保存了较大的对象,而且对象变化较快时,性能下降更加显著.这种特性使得web应用的水平扩展受到了限制. session

squid 代理缓存服务器

Squid cache(简称为Squid)是一个流行的自由软件,它符合GNU通用公共许可证.Squid作为网页服务器的前置cache服务器,可以代理用户向web服务器请求数据并进行缓存,也可以用在局域网中,使局域网用户通过代理上网.Squid主要设计用于在Linux一类系统运行 代理服务器原理 代理服务器接受到请求后,首先与访问控制列表中的访问规则相对照,如果满足规则,则在缓存中查找是否存在需要的信息. 对于Web用户来说,Squid是一个高性能的代理缓存服务器,可以加快内部网浏览Interne

朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素

朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素 [下载文本PDF进行阅读] 本文我会来说说我认为架构评审中应该看的一些点,以及我写设计文档的一些心得.助你在架构评审中过五关斩六将,助你写出能让人收藏点赞的设计文档. 技术架构评审 架构评审或技术方案评审的价值在于集众人的力量大家一起来分析看看方案里是否有坑,方案上线后是否会遇到不可逾越的重大技术问题,提前尽可能把一些事情先考虑到提出质疑其实对项目的健康发展有很大的好处.很多公司都有架构评审委员会都有架构评审的流程,做业务的兄弟要

软件架构设计常用方法-软件架构设计学习第五天(非原创) 发布成功,点击查看文章

文章大纲 一.需考虑问题二.前端架构三.应用层架构四.服务层架构五.存储层架构六.后台架构七.数据采集与监控八.安全架构九.数据中心机房架构十.自动化运维十一.参考文章 一.需考虑问题 1. 研发过程管理困难 (1)依赖管理,每个模块对其他模块的依赖是管理困难的:(2)版本管理:(3)部署管理(搭火车,难以触达到用户):(4)模块组织方式(库工程,源代码级别,没有权限).(5)构建打包痛苦:可能不能打包(2.x安装不上),合并代码搞了很久,编译打包时间过长. 2. 架构设计需考虑情况 (1)业务

spring整合redis客户端及缓存接口设计(转)

一.写在前面 缓存作为系统性能优化的一大杀手锏,几乎在每个系统或多或少的用到缓存.有的使用本地内存作为缓存,有的使用本地硬盘作为缓存,有的使用缓存服务器.但是无论使用哪种缓存,接口中的方法都是差不多.笔者最近的项目使用的是memcached作为缓存服务器,由于memcached的一些限制,现在想换redis作为缓存服务器.思路就是把memached的客户端换成redis客户端,接口依然是原来的接口,这样对系统可以无损替换,接口不变,功能不变,只是客户端变了.本文不介绍缓存的用法,不介绍redis