You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony的Twig与Doctrine缓存短时间自动清除原因排查

Symfony缓存未到配置TTL提前失效问题排查

问题场景

我尝试通过在模板中使用cache标签、在Repository层配置Doctrine缓存的方式降低Symfony网页加载耗时,具体配置如下:

Twig模板缓存配置

{% cache "navbar;v1;" ~ last_updated_at %}
{# loops, conditions and HTML ...#}
{% endcache %}

Repository层Doctrine结果缓存配置

...
return $this->createQueryBuilder('p')
    ->complexQuery...
    ->getQuery()
    ->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
    ->useResultCache(true, 14400)              
    ->getResult();

异常现象

  • 首次加载页面耗时很高,产生大量SQL查询:
    首次加载性能截图
    首次加载SQL查询截图
  • 首次加载后立刻刷新页面,加载速度明显提升:
    缓存命中后性能截图
    缓存命中后SQL查询截图
  • 保持标签页打开,离开15分钟左右返回刷新,页面加载耗时回到首次加载的水平,缓存疑似被提前清除,此时距离配置的14400秒(4小时)TTL还有很久,相关业务数据也没有做更新操作。

问题原因与修复方案

按出现概率从高到低排序,导致该问题的原因有三类:

  • 默认文件缓存被PHP垃圾回收机制误删(概率90%)
    未显式配置缓存驱动时,Symfony dev环境默认使用文件系统缓存,存储路径在项目var/cache/目录下。绝大多数默认PHP环境的session.gc_maxlifetime参数值为1440秒(恰好15分钟),PHP会话垃圾回收触发时,会扫描目录下所有超过15分钟未访问的文件,直接判定为过期删除,完全不会读取代码中设置的14400秒TTL参数。
  • 缓存未绑定独立池,被全局策略提前淘汰
    仅在查询中调用useResultCache(true, 14400)不会强制使用你设置的TTL,如果doctrine.yaml中没有为结果缓存指定独立缓存池,Doctrine会默认使用框架全局的cache.app缓存池。如果该池配置了15分钟的默认生命周期,或是使用Redis作为缓存时配置了allkeys-lru淘汰策略,当缓存内存达到阈值时,15分钟未访问的key会被优先淘汰,不受自身TTL设置限制。
  • Twig缓存键生成逻辑异常
    Twig缓存键拼接了last_updated_at变量,如果该变量存储在session中、或是取值逻辑存在缺陷,15分钟后刷新时生成的缓存键和之前不一致,会直接绕过原有缓存生成新副本,表现和缓存失效完全一致。可以在缓存标签外层记录每次生成的缓存键值,两次刷新对比即可快速排除该问题。

修复步骤

  1. 为Doctrine结果缓存、Twig片段缓存配置独立的Redis缓存驱动,禁止使用默认文件缓存做长期缓存:
    # config/packages/doctrine.yaml
    doctrine:
        orm:
            result_cache_driver:
                type: redis
                host: 127.0.0.1
                port: 6379
                pool: cache.doctrine_result
    
    # config/packages/cache.yaml
    framework:
        cache:
            pools:
                cache.doctrine_result:
                    adapter: cache.adapter.redis
                    default_lifetime: 14400
                cache.twig_fragment:
                    adapter: cache.adapter.redis
                    default_lifetime: 3600
    
  2. Twig cache标签显式指定使用独立缓存池,避免受全局缓存配置影响:
    {% cache "navbar;v1;" ~ last_updated_at with cache.twig_fragment %}
    {# loops, conditions and HTML ...#}
    {% endcache %}
    
  3. 调整Redis缓存实例的淘汰策略为volatile-ttl,禁止使用allkeys-lru策略,避免未过期的缓存key被提前淘汰。
  4. 若暂时无法使用Redis,需将文件缓存的存储路径调整到var/cache/以外的独立目录,同时调大PHP的session.gc_maxlifetime参数,避免垃圾回收误删缓存文件。

内容的提问来源于stack exchange,提问作者Sami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:51:07