Ghost 如何配置内部缓存适配器:MemoryCache、Redis 与按功能覆盖
2026/9/10 18:00:11 网站建设 项目流程

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段。本文基于本仓库文档,说明如何配置MemoryCacheRedis两种内置适配器、如何对单个缓存功能做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指定的适配器是默认缓存适配器,所有未单独指定的功能都使用它;
  • 某个命名功能(如imageSizesgscan)的配置文件里如果带了adapter字段,就覆盖默认值,只用这一个功能走指定适配器;
  • 适配器类名下的配置块(如Redis)是该适配器共享的连接配置,功能对象可以在共享配置基础上再覆盖自己的参数(如keyPrefixttl);
  • 当前命名缓存包括 settings、image sizes、theme validation、stats 以及公开文章与标签数据。功能名应使用归属服务实际请求的名字,不要自己发明第二个名字

全局默认值在 defaults.json 中,adapters.cache.active默认为MemoryCache,并带有空的settingsimageSizesgscan块。功能到适配器的解析在 getCache 中完成:getCache('imageSizes')会去adapter-managercache:imageSizes这个具名适配器实例。

配置文件的优先级(摘自 configuration.md):环境变量高于ghost/core/config.<NODE_ENV>.jsonconfig.local.json,本地文件高于defaults.json的全局默认。因此推荐两种改法:

  1. 本地文件:创建ghost/core/config.local.json(或带注释的config.local.jsonc)写入adapters.cache覆盖项。不要修改被 git 跟踪的ghost/core/config.development.json,也不要提交凭据和本地覆盖。
  2. 环境变量:变量名与配置键一致(含大小写),双下划线表示嵌套;对象值需要用合法 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 dev

Redis块支持的其余连接与行为参数(摘自 AdapterCacheRedis.js 的参数注释):usernameclusterConfig(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保持MemoryCacheimageSizes功能对象里带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块。

验证配置生效

按以下顺序验证(全部来自仓库文档或对应源码):

  1. 确认进程已重启。配置在启动时读取,未重启时旧配置仍然生效。

  2. 打印解析后的配置。按 configuration.md 的调试方法,启用ghost-configdebug 命名空间:

    DEBUG=ghost:*,ghost-config pnpm dev

    启动日志中会输出解析后的完整配置,检查adapters.cache.activeRedis块和你写的功能覆盖项是否如预期。注意:解析后的配置可能包含密码等敏感信息,只在本地查看,不要把未脱敏的输出贴到 issue 或 PR 里。

  3. 观察缓存命中情况。Redis 适配器使用redis-cachedebug 命名空间记录每次读取:

    DEBUG=redis-cache pnpm dev

    日志中会出现形如get <key>: Cache HIT/Cache MISS的行(见 AdapterCacheRedis.js 中的debug(...)调用),可据此确认请求确实经过了 Redis 缓存路径。

  4. 关注适配器发出的指标事件。Redis 适配器在运行时会发出cache-hitcache-misscache-timeoutcache-errorcache-reset以及后台刷新相关指标(cache-background-refresh-*)。其中cache-error会附带get/set/reset操作标识,可用于判断 Redis 侧失败。

限制与已知边界

  • Redis 适配器不支持keys():调用会抛出IncorrectUsageErrorAdapterCacheRedis 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_hashreset()通过更换键前缀的哈希实现 O(1) 失效,但该键不带 TTL,在allkeys-lru/allkeys-random淘汰策略下可能被 Redis 淘汰,淘汰后会静默使整个缓存失效。源码注释建议:需要更严格失效保证时,配置noeviction策略或在带外固定该键。
  • 环境变量与本地文件并存时,同名键以优先级更高者(环境变量)为准;不要把同一个嵌套变量的普通形式和_FILE形式同时设置。
  • 功能名不能自造:按归属服务请求的名字写功能对象,例如imageSizessettingsgscan,写错的名字不会映射到任何实际缓存。

自定义适配器(可选分支)

如果MemoryCacheRedis都不满足需求,可以按 cache-base README 的契约写自定义适配器:继承CacheBase并实现getsetresetkeys,安装到content/adapters/cache/<适配器名>/index.js,然后:

{ "adapters": { "cache": { "active": "MyCache", "MyCache": {} } } }

active的取值必须与文件路径中的适配器名一致(内置Redis适配器的文件头注释明确要求文件名与配置值匹配)。基础类通过npm install @tryghost/adapter-base-cache安装;本仓库内开发该包可用pnpm --filter @tryghost/adapter-base-cache buildpnpm --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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询