频繁执行 cache:flush 会清空共享缓存存储中的大量数据,造成缓存雪崩和首屏延迟。Magento 2 的正确做法是让缓存内容携带实体标签,在实体更新时只清理相关记录。

实体身份标签

自定义实体可实现 IdentityInterface

<?php
declare(strict_types=1);
namespace Alwayly\News\Model;

use Magento\Framework\DataObject\IdentityInterface;

final class Article extends \Magento\Framework\Model\AbstractModel implements IdentityInterface
{
    public const CACHE_TAG = 'alwayly_article';
    protected $_cacheTag = self::CACHE_TAG;
    protected $_eventPrefix = self::CACHE_TAG;

    public function getIdentities(): array
    {
        $id = (int)$this->getId();
        return $id ? [self::CACHE_TAG . '_' . $id] : [self::CACHE_TAG];
    }
}

集合页如果展示多篇文章,应包含每个可见实体的标签以及列表级标签。只返回通用标签会让一次更新清理全部文章缓存;只返回实体标签又可能漏掉新增文章对列表页的影响。

Block 缓存键

public function getCacheKeyInfo(): array
{
    return [
        'ALWAYLY_ARTICLE',
        (int)$this->getStoreId(),
        (int)$this->getRequest()->getParam('id'),
        (string)$this->getData('template'),
    ];
}

public function getIdentities(): array
{
    return $this->article ? $this->article->getIdentities() : [];
}

缓存键描述“哪些上下文会产生不同内容”,标签描述“哪个实体变化时需要清理”。二者不能互相替代。若内容与客户组、币种或 store view 有关,必须加入对应键;包含私有客户数据的 Block 不应进入公共 FPC。

手动精准清理

$this->cache->clean(
    [\Alwayly\News\Model\Article::CACHE_TAG . '_' . $articleId]
);

优先让实体保存流程触发标准清理。只有在数据通过外部流程更新、未经过模型生命周期时,才考虑显式清理,并记录清理原因。

常见错误

  • 更新一个实体就调用 cache:flush
  • 缓存键遗漏 store、客户组或查询参数,导致内容串用。
  • 标签包含随机值,导致永远无法命中失效。
  • 页面由多个 Block 组成,却只有父 Block 提供不完整标签。
  • 把 session 相关内容直接缓存进公共页面。

验证方法

  1. 连续请求同一页面,确认第二次命中缓存。
  2. 修改单个实体,确认相关详情页和列表页更新。
  3. 确认不相关页面仍保持缓存命中。
  4. 在 Varnish 场景检查响应标签与 purge 行为。
  5. 分别验证不同 store view、客户组和币种。

精准缓存失效的目标是同时保证一致性和命中率。出现陈旧数据时,应先检查缓存键与身份标签,而不是把全站 flush 固化到业务代码。