colinmollenhour / cm_diehard
Cm_Diehard:全页缓存
Requires
This package is auto-updated.
Last update: 2024-09-09 01:08:39 UTC
README
本模块旨在简化提供可缓存的HTML页面的过程,避免在访客进行个性化操作(如将产品添加到购物车)时回退到完全动态页面。它提供了多种缓存后端模型供选择,并支持通过Ajax、ESI(边缘包含)或非Ajax JavaScript进行动态块替换。这种打孔操作仅在使用cookie跟踪需要动态化的哪些块(如果有)时进行。后端在处理缓存失效方面也各不相同,使用了一些有趣的技术,其中一些可以实现即使在使用缓存反向代理的情况下也能进行实时缓存失效。渲染技术允许动态块的拥有者仍然为其他用户预热缓存,从而进一步提高缓存命中率。
有关OpenMage的Cm_Diehard示例实现,请参阅Cm_DiehardSample。
后端
目前有三种后端和三种打孔(注入)方法。并非所有后端都支持所有注入方法。后端和所支持的注入方法如下:
- 本地后端
- JavaScript(支持“早期刷新”,类似于Facebook的“BigPipe”方法)
- Ajax
- ESI
- 代理后端
- Ajax
- ESI
- 重新验证后端
- Ajax
- ESI
请注意,所有注入方法使用单个注入点,而不是每个“孔”一个。
本地后端
此后端类似于企业级FPC,但目前使用JavaScript(但不使用Ajax)进行打孔。它默认执行轻量级的缓存响应,并将动态块附加到响应中。此后端的主要目的是在没有反向代理的情况下简化测试,尽管它应该比完全不缓存有更好的性能(在干净安装上提高了600%)。
此后端可以使用OpenMage应用缓存实例(默认),或者通过配置global/diehard_cache/backend
和global/diehard_cache/backend_options
来配置单独配置的缓存实例。
优点
- 直接使用,无需额外要求
- 在确定是否使用缓存响应时提供额外的灵活性
- 缓存清除和失效处理即时且自动
- 实验性:可以在不使用Ajax的情况下进行动态替换
缺点
- OpenMage仍然被加载(但,控制器仅在必要时被分发)
要启用此后端,您必须将其添加到app/etc/local.xml
中的请求处理器
<config> <global> <cache> ... <request_processors> <diehard>Cm_Diehard_Model_Backend_Local</diehard> </request_processors> <restrict_nocache>1</restrict_nocache> <!-- Set to 1 to serve cached response in spite of no-cache request header --> <early_flush>1</early_flush> <!-- Flush cached portion of page before rendering dynamic portion --> </cache> <diehard_cache><!-- OPTIONAL --> <backend>...</backend> <backend_options> ... </backend_options> </diehard_cache> </global> </config>
代理后端
此后端以通用方式呈现响应,并在需要时使用Ajax或ESI进行打孔。缓存失效通过将需要失效的URL列表输出到文件来处理,而实际失效这些URL则由您在反向代理上进行。
重新验证后端
此后端类似于代理后端,因为它使用HTTP头来指示上游反向代理缓存响应,但它使用HTTP的“must-revalidate”缓存控制功能来使反向代理重新验证每个请求。重新验证请求由OpenMage的基础初始化处理,因此在缓存命中时非常轻量。这使得在没有明确在大量边缘服务器上失效大量缓存页面的情况下,可以轻松使用缓存反向代理。安全地使用CDN进行HTML缓存,同时仍享受实时失效!支持Ajax和ESI打孔。
使用ETag或Last-Modified头来通信缓存内容是否已过时,因此请确保您的代理支持重新验证并选择适当的方法。使用弱ETags,因为不支持字节范围请求。
优点
- 将缓存存储卸载到远程服务器,以保持边缘的击中请求的出带宽,从而实现可扩展性。
- 由于每个请求都会重新验证,因此无需在远程服务器上进行直接失效。
- 您可以使用CDN/代理作为您的缓存前端,同时仍然具有无定制集成的即时失效 - 消除奇怪的错误或竞争条件。
- 可以与浏览器的缓存一起使用,在无CDN的dev环境中轻松测试,但有缺点。
- 每个请求仍然会击中PHP,但缓存击中会比未命中更有效率得多,并且使用的带宽可以忽略不计。
反向代理服务器
- Squid(IMS:是,INM:否)
- Nginx(IMS:是,INM:部分)
- Apache(IMS:是,INM:有bug,可能在2.4中已修复)
- Varnish(IMS:是,INM:否(3.x系列的实验-ims分支可能)
肯定支持重新验证的第三方服务
- Cloudfront
可能支持重新验证的第三方服务(未确认)
- Akamai
- Limelight
- EdgeCast
要使用此后端,必须将其添加到app/etc/local.xml
中的缓存请求处理器中
<config> <global> <cache> <request_processors> <diehard>Cm_Diehard_Model_Backend_Revalidating</diehard> </request_processors> </cache> </global> </config>
启用缓存
默认情况下,Cm_Diehard
未启用缓存。有三种启用缓存的方法,但在所有情况下,都建议将您的缓存方案实现为Cm_Diehard
之外的单独模块。对于缓存寿命的假值(0,null,false,''),将禁用当前页面的缓存。
有关OpenMage的Cm_Diehard示例实现,请参阅Cm_DiehardSample。
config.xml
根据config.xml
中的完整操作名称设置秒数
<config> <frontend> <diehard> <actions> <cms_index_index>86400</cms_index_index> <cms_page_view>86400</cms_page_view> </actions> </diehard> </frontend> </config>
布局更新
每个块都会继承一个名为"setDiehardCacheLifetime"的新方法,该方法接受所需寿命(以秒为单位)。布局更新将覆盖config.xml
中的值。
<layout> <cms_page> <reference name="root"> <action method="setDiehardCacheLifetime"><int>300</int></action> </reference> </cms_page> </layout>
事件观察者、控制器、块等。
在发出http_response_send_before
事件之前,您可以使用'diehard'辅助函数设置寿命。该辅助函数以'もちろんです'键添加到OpenMage注册表中,这样您就可以轻松使代码不依赖于Cm_Diehard。
Mage::registry('diehard') && Mage::helper('diehard')->setLifetime(300);
公共与私有域名
您必须注意,当为页面启用缓存时,不要渲染任何特定于单个访客的内容。一个典型的例子是页眉中的“我的购物车”链接,它显示购物车中的商品数量以及“登录”/“退出”链接。有许多处理这些私有或“动态”块的方法。通常,您必须为缓存响应渲染通用的内容,然后为打孔响应定期渲染。以下是一些方法
仅占位符
使用此方法,块将仅渲染一个空的div,用作缓存响应的占位符,然后定期用于动态块注入。此方法的优势在于不需要修改或添加模板,也不需要块类覆盖,只需简单的布局更新即可。
<!-- LAYOUT --> <block type="core/template" name="greeting" template="mymodule/greeting.phtml"> <action method="setBlockIsDynamic"></action> <action method="setSuppressOutput"><param>1</param></action> </block>
<!-- TEMPLATE mymodule/greeting.phtml --> <?php if ( ! Mage::helper('customer')->isLoggedIn() ): ?> <p><?php echo $this->__('Welcome!') ?></p> <?php else: ?> <p><?php echo $this->__('Welcome back, %s!', Mage::helper('customer')->getCustomerName()) ?> <?php endif; ?>
单独的“缓存友好”模板
此方法允许您具有针对缓存友好输出的不同模板,而无需修改任何现有模板或向模板文件添加逻辑。
<!-- LAYOUT --> <block type="core/template" name="greeting" template="mymodule/greeting.phtml"> <action method="setBlockIsDynamic"></action> <action method="setCacheFriendlyTemplate"><param>mymodule/cache-friendly/greeting.phtml</param></action> </block>
<!-- TEMPLATE mymodule/greeting.phtml --> <?php if ( ! Mage::helper('customer')->isLoggedIn() ): ?> <p><?php echo $this->__('Welcome!') ?></p> <?php else: ?> <p><?php echo $this->__('Welcome back, %s!', Mage::helper('customer')->getCustomerName()) ?> <?php endif; ?> <!-- TEMPLATE mymodule/cache-friendly/greeting.phtml --> <p><?php echo $this->__('Welcome!') ?></p>
使用辅助方法添加逻辑
Mage_Core_Block_Abstract类已添加另一个有用的方法,允许您将块实例传递给辅助方法,从而可以在不覆盖块或添加昂贵的事件观察者的情况下对块实例使用逻辑。请注意,只有在页面被缓存的情况下才会调用此方法。
<!-- LAYOUT --> <reference name="checkout_cart_link"> <action method="callHelper"><helper>my_diehard</helper></action> </reference>
<!-- My_Diehard_Helper_Data --> /** * Always render cart link as "My Cart" when caching is active. * * @param Mage_Checkout_Block_Links $block */ public function checkout_cart_link(Mage_Checkout_Block_Links $block) { $parentBlock = $block->getParentBlock(); /* @var $parentBlock Mage_Page_Block_Template_Links */ $text = $block->__('My Cart'); $parentBlock->removeLinkByUrl($block->getUrl('checkout/cart')); $parentBlock->addLink($text, 'checkout/cart', $text, true, array(), 50, null, 'class="top-link-cart"'); }
向模板或块方法添加逻辑
如果只需要对模板的一小部分进行修改以适应缓存响应,并且不想使用单独的模板文件或使用空占位符,则可能更喜欢此方法。
<!-- LAYOUT --> <block type="core/template" name="greeting" template="mymodule/greeting.phtml"> <action method="setBlockIsDynamic"></action> </block>
<!-- TEMPLATE mymodule/greeting.phtml --> <?php if ( Mage::registry('diehard_lifetime') || ! Mage::helper('customer')->isLoggedIn() ): ?> <p><?php echo $this->__('Welcome!') ?></p> <?php else: ?> <p><?php echo $this->__('Welcome back, %s!', Mage::helper('customer')->getCustomerName()) ?> <?php endif; ?>
模块化和向后兼容性
为了保持您的包/主题在未安装Cm_Diehard的情况下仍可操作,同时允许最大的可扩展性,Diehard在布局更新过程中注入了一些特殊的布局更新处理程序。强 DIEHARD_CACHED_default
处理程序将在 default
处理程序之后添加,而 DIEHARD_CACHED_{full_action_name}
处理程序将在 {full_action_name}
处理程序之后添加,只有在缓存启用的情况下,控制器在调用 loadLayout
方法之前渲染的页面才会添加。这提供了以下好处
- 指定仅在请求将被缓存时才应用布局更新的更新。
- 将您的特定于缓存的布局更新与其他布局更新分开。
- 调用Cm_Diehard添加的块方法,而无需使主题依赖于Cm_Diehard的安装。
以下是一个主题的 local.xml
文件示例,该文件可以与或不与Cm_Diehard一起使用
<!-- LAYOUT --> <catalog_product_view> <reference name="content"> <block type="my/custom_block" name="my_block" /> </reference> </catalog_product_view> <DIEHARD_CACHED_catalog_product_view> <reference name="my_block"> <action method="setBlockIsDynamic"></action> <action method="addDefaultIgnored"></action> </reference> </DIEHARD_CACHED_catalog_product_view>
渲染动态块
为了渲染动态块,它们需要被布局访问。默认情况下,在布局处理程序中没有用于渲染动态块的块,它们必须根据需要添加。应使用的布局处理程序是:DIEHARD_DYNAMIC_default
和 DIEHARD_DYNAMIC_{full_action_name}
。这允许您保持动态块渲染的布局轻量级,但与其他任何布局处理程序一样,这些可以继承自其他处理程序,因此通常有两种方法向动态渲染器布局添加块
继承
<!--LAYOUT --> <DIEHARD_DYNAMIC_default> <update handle="default"/> </DIEHARD_DYNAMIC_default>
按需
<!-- LAYOUT --> <DIEHARD_DYNAMIC_default> <block type="core/template" name="greeting" template="mymodule/greeting.phtml"/> </DIEHARD_DYNAMIC_default>
使用此方法时,您必须确保块名称与用于缓存响应的布局中对应的块匹配。块可以直接添加到布局处理程序的根,它们不需要是另一个块的子节点。
添加和删除“忽略”动态块
在某些情况下,指示为动态的块可能并不总是真正是动态的。如果缓存的页面版本仅在特定情况下需要更新,则可以将块添加到“忽略”块列表中,并在需要再次变为动态时从列表中删除。当使用Ajax进行动态块注入时,如果所有动态块都在忽略块列表中,则将完全跳过Ajax请求。
通过布局更新忽略块
块可用的方法是 ignoreBlockUnless()
,它会导致块被忽略除非指定的会话数据存在,以及 ignoreBlockIf()
,它会导致块被忽略如果会话数据存在。
<!-- LAYOUT --> <reference name="greeting"> <action method="ignoreBlockUnless"> <variables> <customer>customer/session::customer_id</customer> </variables> </action> </reference>
通过控制器或块方法忽略块
为了获得更大的灵活性,您可能需要在控制器中添加一些逻辑,一个块准备布局方法或一个事件观察者。
/* CONTROLLER or BLOCK prepareLayout() method or EVENT OBSERVER*/ if (Mage::registry('diehard')) { // Prevent errors in absence of Cm_Diehard module if ($this->getSession()->getSomeVariable()) { Mage::registry('diehard')->removeIgnoredBlock($this); } else { Mage::registry('diehard')->addIgnoredBlock($this); } }
默认忽略块
为了允许正确处理用户在其第一次访问时点击缓存页面的情况,并且无法知道哪些块可以忽略,为每个页面生成一个“默认”忽略块列表,以便在用户尚未被cookie的情况下使用。可以在页面渲染期间使用布局或辅助方法随时将块添加到默认忽略块列表中。
布局
最易于维护的方法可能是在布局中。
<!-- LAYOUT --> <reference name="greeting"> <action method="addDefaultIgnored" /> </reference>
辅助
/* Event Observer, constructor or other */ Mage::helper('diehard')->addDefaultIgnoredBlock('greeting');
在这两个示例中,直到明确从忽略块列表中删除之前,“问候”块将默认对所有用户进行忽略。
点击率监控器
Redis可以用于监控Revalidate后端和本地后端缓存的点击率。要启用此功能,您必须已安装Credis_Client。
然后在 app/etc/local.xml
中设置您的配置
<!-- CONFIG --> <global> ... <diehard> <counter> <enabled>1</enabled> <server>tcp://127.0.0.1:6379/diehard</server> <db>0</db> <full_action_name>1</full_action_name> </counter> </diehard> </global>
上述配置示例使得在每次请求指定的Redis服务器时,击中率和未击中率计数器都会被更新。目前,监控这些统计信息留作您的练习,但这些键很容易查询。
redis-cli get diehard:hit
redis-cli get diehard:miss
redis-cli get diehard:catalog_product_view:hit
etc...
如果统计信息没有被记录,请检查diehard_counter.log
以查找错误。
卸载头信息
由于在初始化完整配置之前需要确定连接状态,因此需要在app/etc/local.xml
中添加“Web > Secure > 卸载头信息”配置,以便对请求产生影响。注意,默认行为在检测安全连接时已经考虑了以下标准:
$_SERVER['HTTPS'] === 'on'
,由Apache设置$_SERVER['SERVER_PORT'] === 443
,由Apache设置X-Forwarded-Proto: https
头信息存在,由许多常见代理设置
如果这些都不成立,但您使用其他头信息来指示安全连接,即使通过管理界面已经设置,也请将其添加到您的app/etc/local.xml
<config> <default> <web> <secure> <offloader_header>SSL_OFFLOADED</offloader_header> </secure> </web> </default> </config>
许可证
本模块采用GPLv3许可证分发。如需获取不同许可证的副本,请联系作者。
Cm_Diehard - OpenMage的全页缓存库。版权所有 (C) 2012 Colin Mollenhour (http://colin.mollenhour.com)
本程序是免费软件:您可以重新分发和/或修改它,只要遵守自由软件基金会发布的GNU通用公共许可证的条款,无论是许可证的第3版,还是(根据您的选择)任何后续版本。
本程序是在希望它有用的愿望下分发的,但不提供任何保证;甚至不提供适销性或特定用途的隐含保证。有关详细信息,请参阅GNU通用公共许可证。
您应该已经随本程序一起收到了GNU通用公共许可证的副本。如果没有,请参阅https://gnu.ac.cn/licenses/