Ghost 如何配置内部缓存适配器:MemoryCache、Redis 与按功能覆盖
【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost
Ghost 的核心内部缓存(settings、图片尺寸、主题校验、统计、公开文章与标签数据等命名缓存)由缓存适配器支撑。默认适配器是MemoryCache,即进程内的内存缓存;当你需要跨进程共享缓存、或只想让某一个功能(例如imageSizes)走 Redis 时,就需要修改环境配置中的adapters.cache段。本文基于本仓库文档,说明如何配置MemoryCache与Redis两种内置适配器、如何对单个缓存功能做adapter覆盖,以及配置后如何验证生效。
适用前提:
- 你在本仓库的 Ghost monorepo 中本地运行 Ghost(
pnpm dev),配置文件规则以 docs/codebase/configuration.md 为准。 - 配置在进程启动时读取,修改任何缓存配置后必须重启 Ghost 进程才会生效。
- 切换到 Redis 前,需要有一个可用的 Redis 实例(主机、端口、密码由你自己提供)。
配置结构与优先级
缓存适配器统一配置在环境配置的adapters.cache段(见 docs/codebase/internal-caching.md):
{ "adapters": { "cache": { "active": "MemoryCache", "Redis": { "host": "localhost", "port": 6379, "password": "" }, "imageSizes": { "adapter": "Redis", "keyPrefix": "2368:image-sizes:", "ttl": 30 }, "gscan": {} } } }工作规则(均来自 internal-caching.md):
active指定的适配器是默认缓存适配器,所有未单独指定的功能都使用它;- 某个命名功能(如
imageSizes、gscan)的配置文件里如果带了adapter字段,就覆盖默认值,只用这一个功能走指定适配器; - 适配器类名下的配置块(如
Redis)是该适配器共享的连接配置,功能对象可以在共享配置基础上再覆盖自己的参数(如keyPrefix、ttl); - 当前命名缓存包括 settings、image sizes、theme validation、stats 以及公开文章与标签数据。功能名应使用归属服务实际请求的名字,不要自己发明第二个名字。
全局默认值在 defaults.json 中,adapters.cache.active默认为MemoryCache,并带有空的settings、imageSizes、gscan块。功能到适配器的解析在 getCache 中完成:getCache('imageSizes')会去adapter-manager取cache:imageSizes这个具名适配器实例。
配置文件的优先级(摘自 configuration.md):环境变量高于ghost/core/config.<NODE_ENV>.json和config.local.json,本地文件高于defaults.json的全局默认。因此推荐两种改法:
- 本地文件:创建
ghost/core/config.local.json(或带注释的config.local.jsonc)写入adapters.cache覆盖项。不要修改被 git 跟踪的ghost/core/config.development.json,也不要提交凭据和本地覆盖。 - 环境变量:变量名与配置键一致(含大小写),双下划线表示嵌套;对象值需要用合法 JSON 语法。
保持默认:MemoryCache
默认配置下 Ghost 已经在用 MemoryCache——一个进程内的Map式存储,实现get/set/reset/keys。单机运行、不需要跨进程共享缓存时,不需要写任何配置,defaults.json已生效。重启后无需额外动作。
注意 MemoryCache 的数据只存在于当前进程内存中,进程重启即丢失;这一点决定了多实例部署时它无法提供共享缓存。
切换到 Redis 适配器
把active设为Redis,连接参数写在Redis共享块下。
方式一:config.local.json(推荐,适合本地开发):
{ "adapters": { "cache": { "active": "Redis", "Redis": { "host": "localhost", "port": 6379, "password": "" } } } }方式二:环境变量(优先级高于本地文件,适合容器环境)。变量名按adapters__cache__...展开,对象值用 JSON:
adapters__cache__active=Redis \ adapters__cache__Redis__host=localhost \ adapters__cache__Redis__port=6379 \ adapters__cache__Redis__password="" pnpm devRedis块支持的其余连接与行为参数(摘自 AdapterCacheRedis.js 的参数注释):username、clusterConfig(Redis Cluster)、storeConfig(额外 redis client 配置,含retryConnectSeconds)、ttl(单位:秒)、getTimeoutMilliseconds(get 操作超时,单位:毫秒)、refreshAheadFactor(0–1,剩余 TTL 低于该比例时触发后台刷新)、keyPrefix(缓存键前缀)、featureName(用于指标过滤)、reuseConnection(是否复用进程内 redis 连接)。文档没有逐项解释所有参数时,请按源码注释为准,不要自行假设默认值。
改完配置后重启 Ghost 进程。
按功能覆盖:让 imageSizes 单独走 Redis
最常见的组合是:默认仍用MemoryCache,只把图片尺寸缓存放到 Redis。这正是 internal-caching.md 给出的示例配置——active保持MemoryCache,imageSizes功能对象里带adapter覆盖,同时Redis共享块提供连接信息:
{ "adapters": { "cache": { "active": "MemoryCache", "Redis": { "host": "localhost", "port": 6379, "password": "" }, "imageSizes": { "adapter": "Redis", "keyPrefix": "2368:image-sizes:", "ttl": 30 }, "gscan": {} } } }这里的关键点:
imageSizes功能因此走 Redis,其余命名缓存仍走MemoryCache;keyPrefix用于构造唯一的缓存键前缀(源码中的示例形如'some_id:image-sizes:'),避免与其他功能或站点共用键空间时互相覆盖;ttl: 30表示该功能缓存条目 30 秒过期(ttl单位为秒);- 若需要多个功能分别覆盖,在
adapters.cache下按各自功能名写对象即可,连接信息共用Redis块。
验证配置生效
按以下顺序验证(全部来自仓库文档或对应源码):
确认进程已重启。配置在启动时读取,未重启时旧配置仍然生效。
打印解析后的配置。按 configuration.md 的调试方法,启用
ghost-configdebug 命名空间:DEBUG=ghost:*,ghost-config pnpm dev启动日志中会输出解析后的完整配置,检查
adapters.cache.active、Redis块和你写的功能覆盖项是否如预期。注意:解析后的配置可能包含密码等敏感信息,只在本地查看,不要把未脱敏的输出贴到 issue 或 PR 里。观察缓存命中情况。Redis 适配器使用
redis-cachedebug 命名空间记录每次读取:DEBUG=redis-cache pnpm dev日志中会出现形如
get <key>: Cache HIT/Cache MISS的行(见 AdapterCacheRedis.js 中的debug(...)调用),可据此确认请求确实经过了 Redis 缓存路径。关注适配器发出的指标事件。Redis 适配器在运行时会发出
cache-hit、cache-miss、cache-timeout、cache-error、cache-reset以及后台刷新相关指标(cache-background-refresh-*)。其中cache-error会附带get/set/reset操作标识,可用于判断 Redis 侧失败。
限制与已知边界
- Redis 适配器不支持
keys():调用会抛出IncorrectUsageError(AdapterCacheRedis does not support keys())。适配器接口要求keys是因为@tryghost/adapter-base-cache的契约(见 cache-base README),该方法已标记为 deprecated,将来可能移除;但不要据此假设 Redis 适配器支持枚举键。 - get 超时与 Redis 失败按 MISS 处理:配置了
getTimeoutMilliseconds后,超时不抛错,而是解析为未命中;Redis 查找期间的错误同样按 MISS 处理并记录cache-error指标(源码见 AdapterCacheRedis.js 的_lookupWithTimeout)。 - 缓存失效依赖
prefix_hash键:reset()通过更换键前缀的哈希实现 O(1) 失效,但该键不带 TTL,在allkeys-lru/allkeys-random淘汰策略下可能被 Redis 淘汰,淘汰后会静默使整个缓存失效。源码注释建议:需要更严格失效保证时,配置noeviction策略或在带外固定该键。 - 环境变量与本地文件并存时,同名键以优先级更高者(环境变量)为准;不要把同一个嵌套变量的普通形式和
_FILE形式同时设置。 - 功能名不能自造:按归属服务请求的名字写功能对象,例如
imageSizes、settings、gscan,写错的名字不会映射到任何实际缓存。
自定义适配器(可选分支)
如果MemoryCache和Redis都不满足需求,可以按 cache-base README 的契约写自定义适配器:继承CacheBase并实现get、set、reset、keys,安装到content/adapters/cache/<适配器名>/index.js,然后:
{ "adapters": { "cache": { "active": "MyCache", "MyCache": {} } } }active的取值必须与文件路径中的适配器名一致(内置Redis适配器的文件头注释明确要求文件名与配置值匹配)。基础类通过npm install @tryghost/adapter-base-cache安装;本仓库内开发该包可用pnpm --filter @tryghost/adapter-base-cache build和pnpm --filter @tryghost/adapter-base-cache test。
以上配置完成并重启后,用DEBUG=ghost:*,ghost-config核对解析结果、用DEBUG=redis-cache核对 HIT/MISS 行为,即完成了从 MemoryCache 到 Redis、再到按功能覆盖的全部配置路径。
【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考