Apache HTTP Server(四)--缓存


Apache HTTP Server(四)--缓存
 
三状态的RFC2616 HTTP缓存
 
HTTP协议包含了内建的对内联缓存机制的支持。mod_cache模块被用来利用这个机制。
 
与简单的双状态键/值缓存(内容过期后会消失)不同,HTTP缓存引用了一个机制来更新过期的内容。一个HTTP缓存项有三种状态:
 
Fresh:不超过保鲜期(freshness lifetime),新鲜的缓存会被直接返回而不调用原始服务器。
Stale: 超过保鲜期,在返回给客户前,需要和原始服务器联系来核查该内容是否仍然新鲜。如果过期则需要从原始服务器得到更新的内容。核查完毕后,内容重新被标记为 新鲜的状态。在一些特殊情况下,服务器也可以向客户返回过期内容。比如原始服务器返回5xx错误,或另一个请求正在更新给定的内容。这些情况下,响应里会 加入Warning头部。  www.2cto.com  
Non Existent:当缓存满时,它可以删除新鲜的或是过期的缓存来腾出空间。它可以发生在任何时候。
 
根据QuickCacheHandler的值(on/off),mod_cache模块可以在两个可能的时间与服务器挂钩:
 
Quick handler phase:在请求处理期间,就在请求被解析后的非常早的阶段。如果在缓存中发现内容,则立即返回,从而几乎所有的请求处理都被绕过。这种模式提供了最快 速的性能,因为主要的服务器处理都被绕过了。但它同样绕过了身份验证(authentication)和授权(authorization)。
Normal Handler phase:发生在请求处理的晚期,在所有请求阶段完成后。这种模式提供了最大化的灵活性,因为缓冲可以潜在发生在过滤链里的被精确控制的点上,同时缓存的内容在返回给用户前可以被过滤或个性化。
 
如果没有在缓存中找到URL,mod_cache会向过滤栈加上一个过滤器,然后退居二线,让普通的请求处理继续执行。如果内容会认定为可缓存,那么内容会被保存以便下次服务,否则内容会被忽略。
如 果在缓存中找到过期的内容,mod_cache模块把请求转换成conditional request。如果原始服务器返回普通的响应,该响应被缓存以代替过期的内容。如果原始服务器返回304 Not Modified响应,那么缓存被重新标记为新鲜,过滤器把缓存返回而不保存它。
 
如果一个虚拟主机有许多别名,那么把UseCanonicalNames设置为on会极大地提升缓存命中率。这是因为主机的名字被用作缓存的键,这个设置会避免主机产生不同的缓存项。
  www.2cto.com  
规 范格式的要缓存的内容应该使用Cache-Control头的max-age或s-maxage域,或包含一个Expires头部来声明一个显式的保鲜 期。同时,服务器定义的保鲜期可以被客户请求里的Cache-Control头部覆盖。这种情况下,请求和响应之间更短的保鲜期被使用。
 
当请求和响应都没有指明保鲜期时,默认的保鲜期被使用。默认情况下它为一小时。CacheDefaultExpire指令可以修改这个值。
如果响应提供了Last-Modified头部但没有提供Expires头部,mod_cache会基于CacheLastModifiedFactor指令的控制对其作出推断。
 
对于本地内容,或者没有定义自己Expires头部的远程内容,mod_expires可能被用来通过加入max-age和Expires来调整保鲜期。
最大的保鲜期也可以使用MaxCacheExpires来控制。
 
如果服务器被设计为基于请求里不同的头部作出不同的响应,比如对于相同URL的支持多种语言,那么HTTP的缓存机制缓存相同URL的相同页面的各种变体。这通过在原始服务里加入一个Vary头部来完成,它指明哪些头部用来区别不同的变体。比如:
Vary: negotiate,accept-language,accept-charset
这时只有在accept-language、accept-charset匹配原始请求时,mod_cache才会使用缓存的内容。
内容的多个变体可以同时存在,moc_cache使用Vary头部已经Vary列出的请求头部的相应的值来决定向客户返回哪种变体。
 
moc_cache依赖于后端存储实现来管理缓存,而moc_cache_disk用来支持到磁盘的缓存。通常模块被配置为:
CacheRoot   "/var/cache/apache/"
CacheEnable disk /
CacheDirLevels 2
CacheDirLength 1
值得注意的是,由于缓存存在本地,操作系统的内存缓存也会应用。所以虽然它们存在磁盘上,但如果它们经常被访问,那么它们很可能会从内存中获得。
 
双状态的键/值共享对象缓存
Apache HTTP服务器提供了低层共享对象缓存,表示如SSL会话,身份凭证的缓存信息,使用socache接口。
每种实现都提供了额外的模块,提供了以下后端:
mod_socache_dbm:基于DBM的共享对象缓存;
mod_socache_dc:基于分布式会话缓存(discache,Distributed session caching)的共享对象缓存;  www.2cto.com  
mod_socache_memcache:基于分布式内存缓存(memcache)的共享对象缓存;
mod_socache_shmcb:基于共享内存(shared memory)的共享对象缓存。
mod_authn_socache模块允许身份验证的结果被缓存,缓解验证后端的负载。
mod_ssl模块使用socache接口提供会话缓存和stapling缓存。
 
特殊文件缓存
在文件系统很慢、或文件处理很耗时的平台上,存在选项在启动时预加载文件到内存。在打开文件很慢的操作系统上,存在选项在启动时打开文件并在内存中缓存句柄。这些选项对访问静态文件很慢的系统很有帮助。
 
打 开文件本身就会造成延迟,特别是网络文件系统。通过为通用文件缓存打开文件的描述符,httpd可以避免这个延迟。httpd当前提供了File- Handle Caching的一个实现,由mod_file_cache提供。它维护了一张文件描述符的表,而不是缓存文件内容。在配置文件里使用CacheFile 指令来指定这种方式的缓存。这个指令告诉httpd启动时打开文件,并在后续对这个文件的访问都重用这个文件句柄。比如:
CacheFile /usr/local/apache2/htdocs/index.html
 
虽然CacheFile使文件本身不被缓存,但这也意味着httpd运行时文件的修改或删除都不会察觉,服务器始终用的是启动时打开的文件内容。
 
从系统内存作出响应的最快的方式。从磁盘甚至是远程网络读取文件会级数级地变慢。
操作系统缓存由操作系统自动完成。而mod_file_cache提供了MMapFile指令把静态文件的内容在启动时映射到内存里,比如:
MMapFile /usr/local/apache2/htdocs/index.html
和CacheFile一样,在httpd启动后文件的修改不会被察觉。
 
由于内存有限,不要过度使用MMapFile。每个httpd的子进程都会复制这块内存,所以要确定映射的文件不能太大,以致于系统交换内存。  www.2cto.com  
 
安全考虑
在默认状态下,QuickCacheHandler被设置为on,mod_cache无法知道被缓存的内容是否被授权,只要缓存未过期,它就会返回缓存的内容。我们可以使用CacheDisable指令或mod_expires来避免缓存。
当QuickCacheHandler被设置为Off时,完成的请求处理被执行,而安全模型保持不变。
 
因为发给终端用户的请求可以从缓存中得到响应,所以缓存本身变为那些希望丑化和干涉内容的人的目标。很重要的一点是我们必须忍受缓存一直对运行httpd的用户是可写的。这和我们提倡的完全相反:保持内容对Apache用户是不可写的。
如果Apache用户让步,比如通过CGI处理的缺陷,那么缓存可能会成为目标。当使用mod_cache_disk时,插入和修改缓存项要相对容易。
这导致了一个相对其它类型的攻击,Apache用户更可能出现的风险。当使用mod_cache_disk时,我们要时刻谨记对httpd进行安全更新,同时运行CGI进程时,尽可能地使用suEXEC作为非Apache用户运行。  www.2cto.com  
 
当作为缓存代理服务器运行httpd时,有潜在的被称为Cache Poisoning的危险。攻击者使用它使得代理服务器从原始服务器得到错误的内容。
例如如果我们运行httpd的DNS服务器是易受攻击的,那么攻击者可能可以控制当从原始服务器请求内容时httpd连接到哪。另一个例子是所谓的requet-smuggling攻击。
 
Vary机制允许相同URL的多个变体可以并肩存在。这个机制也可以变成一个问题,当有一个被熟知的头部,比如User-Agent,在通用情况下有很大的取值范围时,同一个URL可能有上万甚至上亿的变体。
在 其它情况下,有需要根据请求修改一个特定资源的URL,通常是在URL上加上一个“cachebustering”的字符串。如果内容被声明为可缓存的, 那么这些缓存项会把合法缓存项挤出缓存。CacheIgnoreURLSessionIdentifiers指令可以避免这类问题。
 
 
作者 yourtommy

相关内容

    暂无相关文章