<-
Apache HTTP 服务器 2.4 > 内容缓存

缓存指南

该文件补充mod_cachemod_cache_diskmod_file_cachehtcacheclean参考文档。它描述了如何使用Apache HTTP Server的缓存功能来加速Web和代理服务,同时避免常见问题和错误配置。

支持Apache!

也可以看看

最佳

介绍

Apache HTTP服务器提供了一系列缓存功能,这些缓存功能旨在以各种方式提高服务器的性能。

三态RFC2616 HTTP缓存
mod_cache 它的提供程序模块 mod_cache_disk 提供智能的,支持HTTP的缓存。内容本身存储在缓存中,并且mod_cache旨在遵循RFC2616的第13节中描述的控制内容的可缓存性的所有各种HTTP标头和选项 。 mod_cache 适用于简单和复杂的缓存配置,在这些配置中,您要处理代理内容,动态本地内容,或者需要加快对可能速度较慢的磁盘上本地文件的访问。
两状态键/值共享对象缓存
共享对象缓存API(socache)和它的支持模块提供一个服务器宽的键/值基于共享对象缓存。这些模块旨在缓存低级数据,例如SSL会话和身份验证凭据。后端允许将数据存储在服务器范围内的共享内存中,或者数据中心范围内的数据中心中的内存中,例如memcache或distcache。
专用文件缓存
mod_file_cache 提供了在服务器启动时将文件预加载到内存中的功能,并且可以缩短访问时间并在经常访问的文件上保存文件句柄,因为无需在每个请求上都转到磁盘。

为了从本文档中获得最大收益,您应该熟悉HTTP的基础知识,并已阅读《将URL映射到文件系统内容协商的用户指南》 。

最佳

三态RFC2616 HTTP缓存

HTTP协议包含 对RFC2616的第13节所描述的嵌入式缓存机制的内置支持 ,并且mod_cache可以使用该 模块来利用这一点。

与简单的两个状态键/值高速缓存不同,该内容在不再新鲜时会完全消失,HTTP高速缓存包含一种机制,用于保留陈旧的内容,并询问源服务器此陈旧的内容是否已更改,如果未更改,请使其再次新鲜。

HTTP缓存中的条目存在以下三种状态之一:

新鲜
如果内容足够新(未超过其新鲜度),则认为它是新鲜的。HTTP缓存可以免费提供新鲜的内容,而无需对原始服务器进行任何调用。
陈旧

如果内容太旧(比其新鲜度寿命长),则认为它是陈旧的。HTTP缓存应与原始服务器联系,并在将过时的内容提供给客户端之前检查内容是否仍然新鲜。如果仍然无效,原始服务器将使用替换内容进行响应,或者理想情况下,原始服务器将使用代码进行响应以告诉缓存内容仍然是最新的,而无需再次生成或发送内容。内容再次变得新鲜,并且循环继续。

HTTP协议确实允许高速缓存在某些情况下为过时的数据提供服务,例如,尝试用原始服务器刷新数据失败并出现5xx错误时,或者当另一个请求已经在刷新给定条目的过程中时。在这些情况下,Warning标题会添加到响应中。

不存在的
如果缓存已满,它将保留从缓存中删除内容以腾出空间的选项。内容可以随时删除,并且可以是陈旧或新鲜的。该htcacheclean工具可以在关闭的基础上运行一次,或者部署为守护程序,以保持给定大小,或inode的给定数量内的高速缓存的大小。该工具将尝试删除过时的内容,然后再尝试删除新的内容。

有关HTTP缓存工作原理的完整详细信息,请参见 RFC2616的第13节

与服务器的交互

mod_cache模块挂接到中视的价值的两种可能的地方服务器 CacheQuickHandler指令:

快速处理程序阶段

此阶段发生在请求处理期间的很早,就在解析请求之后。如果在缓存中找到了内容,则将立即提供该内容,并且几乎所有请求处理都将被绕过。

在这种情况下,缓存的行为就像是已“固定”在服务器的前端。

此模式可提供最佳性能,因为绕过大多数服务器处理。但是,此模式也会绕过服务器处理的身份验证和授权阶段,因此,在此模式很重要时,应谨慎选择此模式。

mod_cache在此阶段运行时,带有“授权”标头的请求(例如,HTTP基本身份验证)既不可缓存也不可从缓存中获取。

正常处理程序阶段

在所有请求阶段完成之后,此阶段发生在请求处理的后期。

在这种情况下,缓存的行为就像是已“固定”在服务器的背面。

此模式提供了最大的灵活性,因为存在潜在的缓存发生在过滤器链中精确控制的位置的可能性,并且可以在将缓存的内容发送给客户端之前对其进行过滤或个性化。

如果在缓存中找不到URL,mod_cache 则将一个过滤器添加到过滤器堆栈中,以便记录对缓存的响应,然后放下脚步,从而继续进行正常的请求处理。如果确定内容可缓存,则将内容保存到缓存中以备将来使用,否则将忽略该内容。

如果在缓存中找到的内容是陈旧的,则 mod_cache模块会将请求转换为 条件请求。如果原始服务器以正常响应进行响应,则将缓存正常响应,替换已缓存的内容。如果原始服务器使用304 Not Modified响应进行响应,则内容将再次标记为新鲜,并且缓存的内容由过滤器提供,而不是保存。

改善缓存命中

当虚拟主机被许多不同的服务器别名之一识别时,确保将UseCanonicalName其设置为On可以大大提高缓存命中率。这是因为在缓存键中使用了服务内容的虚拟主机的主机名。将设置设置为On 具有多个服务器名称或别名的虚拟主机将不会产生不同的缓存实体,而是根据规范的主机名缓存内容。

新鲜寿命

旨在缓存的格式正确的内容应使用Cache-Control 标头max-ages-maxage字段或通过包含Expires标头来声明显式的新鲜度生存期。

同时,当客户端Cache-Control在请求中提出自己的标头时,客户端可以覆盖原始服务器定义的新鲜度生存期 。在这种情况下,将获得请求和响应之间的最低新鲜度生存期。

当请求或响应中缺少此新鲜度生存期时,将应用默认的新鲜度生存期。高速缓存的实体的默认新鲜度生存期为一小时,但是可以使用CacheDefaultExpire伪指令轻松地将其覆盖。

如果响应中不包含Expires标头,但确实包含Last-Modified标头,则mod_cache 可以基于启发式来推断新鲜度生命周期,可以通过使用CacheLastModifiedFactor伪指令来对其进行控制。

对于本地内容或未定义其自己的Expires标头的远程内容 ,mod_expires可通过添加max-age和 来调整新鲜度寿命Expires

最大新鲜度寿命也可以通过使用来控制 CacheMaxExpire

条件请求简要指南

当内容从缓存中过期并变得陈旧,而不是传递原始请求时,httpd将修改该请求以使其成为有条件的。

ETag原始缓存的响应中存在标头时,mod_cache会将If-None-Match标头添加 到源服务器的请求中。当Last-Modified原始缓存的响应中存在标头时,mod_cache会将If-Modified-Since标头添加 到源服务器的请求中。执行这两个操作之一会使请求成为条件请求 。

当原始服务器接收到条件请求时,原始服务器应检查ETag或Last-Modified参数是否已更改,以适合该请求。如果不是,则原点应以简洁的“ 304未修改”响应进行响应。这向缓存发出信号,表明过时的内容仍然是新鲜的,应将其用于后续请求,直到再次达到该内容的新的新鲜度生存期为止。

如果内容已更改,则将内容作为请求的开始条件。

有条件的请求有两个好处。首先,当向源服务器发出这样的请求时,如果来自源的内容与高速缓存中的内容相匹配,则可以容易地确定这一点,而无需传输整个资源的开销。

其次,将设计一种设计良好的原始服务器,以使产生条件请求的成本大大低于完整响应。对于静态文件,通常只涉及对的调用stat()或类似的系统调用,以查看文件的大小或修改时间是否已更改。这样,即使本地内容没有更改,它仍然可以从缓存中更快地提供。

原始服务器应尽实际可能支持条件请求,但是,如果不支持条件请求,则原始服务器将以请求不是有条件的方式进行响应,并且缓存将以内容已更改的方式进行响应并保存新内容到缓存。在这种情况下,缓存的行为类似于简单的两个状态缓存,其中内容实际上是新鲜的或已删除。

可以缓存什么?

RFC2616第13.4节“响应缓存能力”中定义了HTTP缓存可以缓存的响应的完整定义 ,可以总结如下:

  1. 必须为此URL启用缓存。请参见CacheEnableCacheDisable指令。
  2. 如果响应的HTTP状态代码不是200、203、300、301或410,则它还必须指定“ Expires”或“ Cache-Control”标头。
  3. 该请求必须是HTTP GET请求。
  4. 如果响应包含“ Authorization:”标头,则它还必须在“ Cache-Control:”标头中包含“ s-maxage”,“必须重新验证”或“ public”选项,否则将不会被缓存。
  5. 如果URL包含查询字符串(例如,来自HTML表单GET方法的查询字符串),则除非响应通过包含“ Expires:”标头或“缓存”的max-age或s-maxage指令指定了显式到期,否则将不会缓存该查询字符串-Control:“标头,根据RFC2616第13.9和13.2.1节的规定。
  6. 如果响应的状态为200(OK),则响应还必须包括“ Etag”,“ Last-Modified”或“ Expires”标头中的至少一个,或者该响应的max-age或s-maxage指令。 “ Cache-Control:”标头,除非CacheIgnoreNoLastMod 已使用该 指令另外要求。
  7. 如果响应在“ Cache-Control:”标头中包含“ private”选项,则除非将CacheStorePrivate其用于其他要求,否则不会存储该响应 。
  8. 同样,如果响应在“ Cache-Control:”标头中包含“ no-store”选项,则除非CacheStoreNoStore已使用,否则不会将其存储 。
  9. 如果响应包含包含所有匹配项“ *”的“ Vary:”标头,则不会存储该响应。

什么不应该被缓存?

应当由客户端创建请求,或者由原始服务器构造响应,以通过正确设置Cache-Control标头来决定内容是否应可缓存 ,并且mod_cache应单独使用以实现客户端或服务器的意愿作为适当的。

时间敏感的内容,或随HTTP协商未涵盖的请求的具体情况而变化的内容,不应被缓存。此内容应使用Cache-Control标头声明自身不可缓存。

如果内容经常更改(以分钟或秒的新鲜度表示),则仍然可以缓存该内容,但是非常希望源服务器正确支持 条件请求,以确保不必定期生成完整的响应。

可以通过智能使用Vary响应头来缓存基于客户端提供的请求标头而变化的内容。

可变/协商内容

当原始服务器设计为根据请求中标头的值响应不同的内容(例如,在同一URL上提供多种语言)时,HTTP的缓存机制可以在同一URL上缓存同一页面的多个变体。

这是通过原始服务器添加Vary标头来完成的,以指示在确定两个变体是否彼此不同时缓存必须考虑哪些标头。

例如,如果接收到带有变化报头的响应,例如;

Vary: negotiate,accept-language,accept-charset

mod_cache 只会将缓存的内容提供给请求者,这些请求者的accept-language和accept-charset标头与原始请求的标头匹配。

内容的多个变体可以并排缓存, mod_cache使用Vary标题和请求标头列出的相应值Vary 来决定要返回给客户端的众多变体中的哪一个。

最佳

缓存设置示例

缓存到磁盘

mod_cache模块依靠特定的后端存储实现来管理缓存,并提供了到磁盘的缓存mod_cache_disk来支持该缓存 。

通常,模块将被配置为:

CacheRoot   "/var/cache/apache/"
CacheEnable disk /
CacheDirLevels 2
CacheDirLength 1

重要的是,由于缓存文件是本地存储的,因此操作系统内存中的缓存通常也将应用于其访问。因此,尽管文件存储在磁盘上,但是如果经常访问它们,则操作系统很可能会确保从内存中实际获取文件。

了解缓存存储

要将项目存储在缓存中,mod_cache_disk请为请求的URL创建一个22个字符的哈希。此哈希值包含URL的主机名,协议,端口,路径和任何CGI参数,以及Vary标头定义的元素,以确保多个URL不会相互冲突。

每个字符可以是64个不同字符中的任何一个,这意味着总共有64 ^ 22个可能的散列。例如,URL可能被哈希到xyTGxSMO2b68mBCykqkp1w。此哈希用作缓存中该URL特定文件的命名的前缀,但是首先根据CacheDirLevelsCacheDirLength 指令将其拆分为目录。

CacheDirLevels 指定应该有多少级子目录,并 CacheDirLength 指定每个目录中应有多少个字符。使用上面给出的示例设置,哈希将转换为文件名前缀 /var/cache/apache/x/y/TGxSMO2b68mBCykqkp1w

该技术的总体目标是减少特定目录中可能存在的子目录或文件的数量,因为大多数文件系统会随着该数量的增加而变慢。设置为“ 1”时, CacheDirLength 在任何特定级别最多可以有64个子目录。设置为2时,可以有64 * 64个子目录,依此类推。除非有充分的理由,否则CacheDirLength 建议将设置设置为“ 1” 。

设置 CacheDirLevels 取决于您预期在缓存中存储多少文件。通过在以上示例中使用的设置“ 2”,最终可以创建总共4096个子目录。缓存了100万个文件,每个目录大约有245个缓存URL。

每个URL在高速缓存存储区中至少使用两个文件。通常,会有一个“ .header”文件,其中包括有关URL的元信息(例如,何时到期)和一个“ .data”文件,该文件是要提供的内容的逐字复制。

在通过“ Vary”标头协商内容的情况下,将为所讨论的URL创建“ .vary”目录。该目录将具有多个“ .data”文件,它们对应于不同协商的内容。

维护磁盘缓存

mod_cache_disk模块不会尝试调节高速缓存所使用的磁盘空间量,尽管它会在出现任何磁盘错误时正常运行,并且表现出好像从未出现过高速缓存一样的状态。

而是使用htcacheclean工具与httpd一起提供,该工具可让您定期清理缓存。确定htcacheclean的运行频率以及用于缓存的目标大小多少有些复杂,选择最佳值可能需要反复试验。

htcacheclean具有两种操作模式。它可以作为持久守护程序运行,也可以从cron定期运行。htcacheclean可能需要一个小时或更长时间来处理非常大(数十GB)的高速缓存,如果从cron运行它,建议您确定一次典型运行需要多长时间,以避免一次运行多个实例。

还建议为htcacheclean选择适当的“ nice”级别,以便该工具在服务器运行时不会引起过多的磁盘io。


图1:典型的高速缓存增长/清理顺序。

因为mod_cache_disk本身并不关注使用了多少空间,所以应确保将 htcacheclean配置为在进行清理后留出足够的“增长空间”。

缓存到memcached

使用该mod_cache_socache模块,mod_cache 可以缓存来自各种实现方式(也称为“提供者”)的数据。mod_socache_memcache例如,使用该 模块,可以指定将 memcached用作后端存储机制。

通常,模块将配置为:

CacheEnable socache /
CacheSocache memcache:memcd.example.com:11211

memcached可以通过将其他服务器附加到以CacheSocache memcache: 逗号分隔的行的末尾来指定其他服务器:

CacheEnable socache /
CacheSocache memcache:mem1.example.com:11211,mem2.example.com:11212

此格式还与其他各种mod_cache_socache 提供程序一起使用。例如:

CacheEnable socache /
CacheSocache shmcb:/path/to/datafile(512000)
CacheEnable socache /
CacheSocache dbm:/path/to/datafile
最佳

通用两状态键/值共享对象缓存

Apache HTTP服务器提供了一个低级共享对象缓存,用于在socache界面中缓存诸如SSL会话或身份验证凭据之类的信息

为每个实现提供了附加模块,提供了以下后端:

mod_socache_dbm
基于DBM的共享库。
mod_socache_dc
基于Distcache的共享库。
mod_socache_memcache
基于Memcache的共享对象缓存。
mod_socache_shmcb
基于共享内存的共享对象缓存。

缓存身份验证凭证

mod_authn_socache模块允许缓存身份验证结果,从而减轻了身份验证后端的负担。

缓存SSL会话

mod_ssl模块使用该socache接口提供会话缓存和装订缓存。

最佳

专用文件缓存

在文件系统可能很慢或文件句柄昂贵的平台上,可以选择在启动时将文件预加载到内存中。

在打开文件的速度较慢的系统上,存在用于在启动时打开文件并缓存文件句柄的选项。这些选项可在访问静态文件较慢的系统上提供帮助。

文件句柄缓存

打开文件的行为本身可能会导致延迟,特别是在网络文件系统上。通过维护常用文件的打开文件描述符的缓存,httpd可以避免这种延迟。当前,httpd提供了一种文件句柄缓存的实现。

缓存文件

httpd中存在的最基本的缓存形式是所提供的文件句柄缓存mod_file_cache。该缓存不维护文件内容,而是维护一个打开文件描述符表。使用CacheFile 伪指令在配置文件中指定以这种方式缓存的文件。

CacheFile指令指示httpd在启动时打开文件,并重新使用此文件句柄进行所有后续对该文件的访问。

CacheFile /usr/local/apache2/htdocs/index.html

如果打算以这种方式缓存大量文件,则必须确保适当设置操作系统对打开文件数的限制。

尽管使用CacheFile 不会导致文件内容本身被缓存,但这确实意味着如果在httpd运行时文件发生更改,这些更改将不会被接收。该文件将与启动httpd时的文件一致。

如果在httpd运行时删除了文件,它将继续维护一个打开的文件描述符,并像启动httpd时一样提供文件。这通常也意味着,尽管该文件将被删除并且不会显示在文件系统上,但是直到httpd停止并且文件描述符关闭后,额外的可用空间才能恢复。

内存中缓存

通常,直接从系统内存中进行服务是提供内容的最快方法。从磁盘控制器,或更糟的是从远程网络读取文件,速度要慢几个数量级。磁盘控制器通常涉及物理过程,并且网络访问受到可用带宽的限制。另一方面,内存访问仅需纳秒。

虽然系统内存并不便宜,但字节到字节是迄今为止最昂贵的存储类型,确保有效使用它很重要。通过在内存中缓存文件,可以减少系统上可用的内存量。就像我们将看到的那样,就操作系统缓存而言,这并不是什么大问题,但是在使用httpd自己的内存缓存时,重要的是要确保不要为缓存分配过多的内存。否则,系统将被迫换出内存,这可能会降低性能。

操作系统缓存

几乎所有现代操作系统都在内核直接管理的内存中缓存文件数据。这是一项强大的功能,并且在大多数情况下,操作系统会使其正确运行。例如,在Linux上,让我们看看第一次和第二次读取文件所花费的时间有所不同。

colm@coroebus:~$ time cat testfile > /dev/null
real    0m0.065s
user    0m0.000s
sys     0m0.001s
colm@coroebus:~$ time cat testfile > /dev/null
real    0m0.003s
user    0m0.003s
sys     0m0.000s

即使对于这个小文件,读取文件所花费的时间也有巨大差异。这是因为内核已将文件内容缓存在内存中。

通过确保系统上有“备用”内存,可以确保越来越多的文件内容将存储在此高速缓存中。这可能是内存中缓存的一种非常有效的方法,并且完全不需要额外的httpd配置。

此外,由于操作系统知道何时删除或修改文件,因此它可以在必要时自动从缓存中删除文件内容。与httpd的内存中缓存相比,这是一个很大的优势,后者无法知道文件何时更改。

尽管自动操作系统缓存具有性能和优点,但在某些情况下,httpd可能会更好地执行内存中缓存。

MMapFile缓存

mod_file_cache提供该 MMapFile指令,使您可以在开始时使用httpd将静态文件的内容httpd映射到内存中(使用mmap系统调用)。httpd将使用内存中的内容来进行对该文件的所有后续访问。

MMapFile /usr/local/apache2/htdocs/index.html

与该 CacheFile指令一样,httpd启动后将不会拾取这些文件中的任何更改。

MMapFile 指令不会跟踪其分配了多少内存,因此您必须确保不要过度使用该指令。每个httpd子进程都会复制该内存,因此确保映射的文件不会太大而导致系统交换内存至关重要。

最佳

安全注意事项

授权和访问控制

mod_cacheCacheQuickHandler设置为的 默认状态下 使用On非常类似于将缓存的反向代理连接到服务器的前端。缓存模块将为请求提供服务,除非它确定应该像外部缓存一样查询原始服务器,这将大大改变httpd的安全模型。

由于遍历文件系统层次结构以检查潜在 .htaccess文件将是一项非常昂贵的操作,部分使缓存不足(加快请求速度),因此 mod_cache无法决定是否授权缓存实体进行服务。换一种说法; 如果 mod_cache已经缓存了某些内容,则只要该内容尚未过期,就会从缓存中提供该内容。

例如,如果您的配置允许通过IP地址访问资源,则应确保不缓存此内容。您可以使用CacheDisable 指令或来执行此操作mod_expires。不用检查, mod_cache就像反向代理一样,将在提供内容时缓存内容,然后将其提供给任何IP地址上的任何客户端。

CacheQuickHandler 伪指令设置Off为时,将执行整个请求处理阶段,并且安全模型保持不变。

本地漏洞

由于可以从缓存中满足对最终用户的请求,因此缓存本身可以成为希望破坏或干扰内容的用户的目标。重要的是要记住,缓存必须始终由运行httpd的用户可写。这与通常建议的情况下保持所有Apache用户不可写的内容形成鲜明对比。

如果Apache用户受到损害(例如,由于CGI进程中的缺陷),则可能会将缓存作为目标。使用时mod_cache_disk,插入或修改缓存的实体相对容易。

与可能以Apache用户身份进行的其他类型的攻击相比,这带来了较高的风险。如果要使用,mod_cache_disk请记住这一点-确保在宣布安全升级后升级httpd,并在可能的情况下使用suEXEC作为非Apache用户运行CGI进程。

缓存中毒

当将httpd作为缓存代理服务器运行时,也有可能发生所谓的缓存中毒。缓存中毒是攻击的广义术语,其中,攻击者使代理服务器从原始服务器检索不正确的(通常是不受欢迎的)内容。

例如,如果运行httpd的系统使用的DNS服务器容易受到DNS缓存中毒的攻击,则攻击者可以从原始服务器请求内容时控制httpd连接到的位置。另一个例子是所谓的HTTP请求走私攻击。

本文档不是深入讨论HTTP请求走私的正确位置(相反,请尝试使用您喜欢的搜索引擎),但是请务必注意,可以发出一系列请求并利用以下漏洞进行操作很重要。原始网络服务器,以便攻击者可以完全控制代理检索的内容。

拒绝服务/ Cachebusting

Vary机制允许同一个URL的多个变体并排缓存。根据客户端提供的标头值,缓存将选择正确的变体以返回到客户端。当尝试更改已知在正常使用情况下包含多种可能值的User-Agent标头(例如标头)时,此机制可能会成为问题。根据特定网站的受欢迎程度,可以为同一URL创建成千上万个重复的缓存条目,从而排挤缓存中的其他条目。

在其他情况下,可能需要在每个请求上更改特定资源的URL,通常是通过在URL上添加“ cachebuster”字符串来实现。如果此内容被服务器声明为可缓存很长时间,则这些条目可能会挤出缓存中的合法条目。尽管mod_cache 提供了 CacheIgnoreURLSessionIdentifiers 指令,但应谨慎使用此指令以确保下游代理或浏览器缓存不会受到相同的拒绝服务问题。

可用语言: zh  |  fr  |  TR 

最佳

注释

注意:
这不是“问答”部分。此处放置的评论应指向有关改进文档或服务器的建议,如果实施或被认为无效/偏离主题,我们的主持人可以将其删除。有关如何管理Apache HTTP Server的问题,应直接指向我们的IRC频道#httpd(位于Freenode上),或发送至我们的邮件列表
目前,此页面已禁用评论。