文档目录
缓存策略

简介

本技术文档聚焦 DouPHP 后台服务层的缓存策略,围绕缓存层级、键生成、失效机制、一致性保障、容量与内存优化、监控与故障恢复等主题展开。结合仓库中现有实现(如 URL 字段缓存预热、模板缓存清理、可插拔的缓存适配器抽象),给出面向生产环境的最佳实践与落地建议。

项目结构

DouPHP 在后台侧提供了两类与缓存相关的实现:

  • 运行时数据缓存:通过可插拔的缓存适配器抽象(LtCacheAdapter)与连接管理(LtCacheHandle/LtCacheConnectionManager)提供 get/add/update/del 能力,适配 Memcache/Memcached 等后端。
  • 文件系统缓存:模板编译产物、静态资源等以文件形式落盘,并提供统一的清理入口(CacheClearService)。
graph TB
A["业务服务<br/>控制器/服务层"] --> B["URL 字段缓存预热<br/>UrlBuilder::warmupFieldCache()"]
A --> C["模板/文件缓存清理<br/>CacheClearService::clearCache()"]
A --> D["可插拔缓存接口<br/>LtCacheAdapter"]
D --> E["Memcache 适配器<br/>CacheAdapterMemcache"]
D --> F["Memcached 适配器<br/>CacheAdapterMemcached"]
A --> G["数据库访问门面<br/>DB Facade"]

核心组件

  • 缓存适配器抽象:定义统一接口 add/get/update/del/connect,屏蔽底层存储差异。
  • 缓存句柄:封装连接管理与适配器选择,对外暴露标准操作。
  • 配置构建器:支持多组节点、主从角色、默认配置合并,便于扩展不同环境。
  • 模板缓存清理:提供删除指定目录的能力,用于发布/升级后清理编译产物。
  • URL 字段缓存预热:批量回填 slug/created_at 等字段,减少重复查询。

架构总览

下图展示后台服务层与缓存相关组件的交互关系:业务服务调用 URL 字段缓存预热与模板缓存清理;同时可通过 LtCacheAdapter 系列进行通用缓存读写;数据库访问通过 DB 门面完成。

sequenceDiagram
participant Svc as "后台服务"
participant Url as "UrlBuilder"
participant Cache as "LtCacheHandle"
participant Adapter as "LtCacheAdapter"
participant DB as "DB Facade"
participant FS as "文件系统"
Svc->>Url : 触发字段缓存预热
Url->>DB : 批量查询缺失字段
DB-->>Url : 返回字段值
Url->>Url : 写入进程内缓存映射
Svc->>Cache : get/add/update/del(key, table)
Cache->>Adapter : 转发请求
Adapter-->>Cache : 返回结果
Svc->>FS : 清理模板缓存目录
FS-->>Svc : 完成

详细组件分析

组件A:URL 字段缓存预热(进程内缓存)

  • 目标:避免对同一批 ID 的字段(如 slug、created_at)重复查询,提升渲染与路由组装效率。
  • 流程要点:
    • 计算当前批次缺失的 ID 集合。
    • 若存在缺失,发起一次 IN 查询批量获取字段。
    • 将结果回填到进程内缓存映射,并对未命中的 ID 填充默认值,防止后续重复穿透。
  • 复杂度:时间 O(N+M),空间 O(M),其中 N 为请求 ID 数,M 为缺失 ID 数。
  • 适用场景:列表页、详情页批量渲染、路由 slug 解析等读多写少场景。
flowchart TD
Start(["进入 warmupFieldCache"]) --> CheckLocal["检查进程内缓存是否已命中"]
CheckLocal --> |全部命中| End(["结束"])
CheckLocal --> |存在缺失| BuildMiss["构造缺失ID集合"]
BuildMiss --> QueryDB["批量查询缺失字段"]
QueryDB --> FillCache["回填进程内缓存并补默认值"]
FillCache --> End

组件B:模板/文件缓存清理(文件系统缓存)

  • 目标:在主题/模块更新或发布后,清理编译后的模板缓存目录,确保新模板生效。
  • 行为:递归删除指定目录及其子目录内容。
  • 使用点:主题初始化流程中调用,保证部署后视图正确刷新。

组件C:登录流程中的缓存清理(事件副作用)

  • 目标:在管理员登录后执行必要的副作用,包括清理缓存,确保权限与界面状态一致。
  • 集成方式:通过依赖注入将缓存清理服务注入登录编排服务,在成功登录后触发。

组件D:可插拔缓存适配器(通用 KV 缓存)

  • 抽象:LtCacheAdapter 定义 connect/add/get/update/del 方法,屏蔽底层存储差异。
  • 句柄:LtCacheHandle 负责连接管理与适配器选择,对外暴露统一 API。
  • 配置:LtCacheConfigBuilder 支持多组节点、主从角色与默认配置合并。
  • 适配器实现:
    • Memcache 适配器:基于 memcache_connect 建立连接,key 前缀采用“表名-键”形式。
    • Memcached 适配器:基于 Memcached 扩展,同样以“表名-键”作为真实 key。
classDiagram
class LtCacheAdapter {
+connect(hostConf)
+add(key, value, ttl, tableName, connectionResource)
+del(key, tableName, connectionResource)
+get(key, tableName, connectionResource)
+update(key, value, ttl, tableName, connectionResource)
}
class LtCacheHandle {
+configHandle
+group
+node
+role
+connectionManager
+connectionResource
+init()
+add(key, value, ttl, tableName)
+del(key, tableName)
+get(key, tableName)
+update(key, value, ttl, tableName)
-initConnection()
}
class CacheAdapterMemcache {
+connect(hostConf)
+add(...)
+del(...)
+get(...)
+update(...)
-getRealKey(tableName, key)
}
class CacheAdapterMemcached {
+connect(hostConf)
+add(...)
+del(...)
+get(...)
+update(...)
-getRealKey(tableName, key)
}
LtCacheHandle --> LtCacheAdapter : "委托"
CacheAdapterMemcache ..|> LtCacheAdapter
CacheAdapterMemcached ..|> LtCacheAdapter

组件E:配置构建器(多节点/主从)

  • 功能:按 group/node/role 组织缓存服务器配置,支持默认配置继承与覆盖。
  • 用途:便于在不同环境(开发/测试/生产)切换不同的缓存集群与角色。

依赖关系分析

  • 业务服务依赖:
    • URL 字段缓存预热依赖数据库访问(DB Facade)进行批量查询。
    • 模板缓存清理依赖文件系统工具。
    • 通用 KV 缓存依赖 LtCacheAdapter 及其具体实现。
  • 耦合度:
    • 通过 LtCacheAdapter 解耦业务与具体缓存后端,降低耦合。
    • URL 预热与 DB 访问通过门面隔离,便于替换与测试。
  • 外部依赖:
    • Memcache/Memcached 扩展需在生产环境启用。
    • 文件系统路径需具备读写权限。
graph LR
Svc["后台服务"] --> U["UrlBuilder"]
Svc --> H["LtCacheHandle"]
H --> A1["CacheAdapterMemcache"]
H --> A2["CacheAdapterMemcached"]
U --> D["DB Facade"]
Svc --> F["文件系统"]

性能考量

  • 热点数据缓存:
    • 优先使用进程内缓存(如 URL 字段缓存)减少跨进程/网络开销。
    • 对于跨进程共享的热点数据,使用 Memcache/Memcached 作为二级缓存。
  • 查询结果缓存:
    • 针对高并发读、低频率写的查询结果,设置合理 TTL,并结合版本号或时间戳作为键的一部分,避免脏读。
  • 配置信息缓存:
    • 系统配置变更时主动失效对应缓存键,或在配置加载时附带版本标识。
  • 批量操作:
    • 使用 IN 查询批量回填字段,减少往返次数。
  • 内存优化:
    • 控制进程内缓存大小,避免无限增长;对大对象考虑序列化压缩。
    • 对 KV 缓存设置合理的过期时间与最大内存限制。

故障排查指南

  • 模板缓存未刷新:
    • 确认是否在主题/模块更新后调用了缓存清理服务。
    • 检查目标目录是否存在及是否有写入权限。
  • 登录成功后缓存不一致:
    • 检查登录流程是否正确触发缓存清理逻辑。
  • 缓存键冲突:
    • 确认键生成策略包含足够区分维度(如表名前缀、业务域、版本号)。
  • 缓存不可用:
    • 检查 Memcache/Memcached 扩展是否启用、连接参数是否正确。
    • 观察适配器返回的错误码与日志。

结论

DouPHP 后台服务层在缓存方面提供了进程内预热、文件系统缓存清理以及可插拔的 KV 缓存抽象,能够满足常见的热点数据、查询结果与配置信息的缓存需求。结合合理的键生成策略、失效机制与一致性方案,可在保证数据正确性的前提下显著提升性能。建议在关键路径引入监控指标与告警,持续优化缓存命中率与内存占用。

附录

  • 缓存层级建议:
    • L1 进程内缓存:短生命周期、高热度数据(如 URL 字段、小字典)。
    • L2 分布式缓存:跨进程共享的热点数据(如商品详情、配置快照)。
    • L3 持久化存储:数据库与文件存储,作为最终一致性来源。
  • 键生成策略建议:
    • 采用“域:实体:标识:版本”的结构,便于局部失效与灰度。
  • 失效机制建议:
    • 写扩散:更新时主动删除或更新相关缓存键。
    • 读扩散:读取时发现过期则回源并重建缓存。
  • 一致性保障:
    • 先更新数据库,再删除缓存;或采用延迟双删策略。
    • 对强一致场景,增加版本号校验或分布式锁。
  • 监控与恢复:
    • 记录命中率、延迟、错误率;异常时自动降级至直连数据库。
    • 定期巡检缓存集群健康与内存水位。
添加日期:2026-10-05