配置缓存后端
如何配置Apollo Server的缓存
多数Apollo Server的功能利用了缓存后端(这些功能包括 自动持久化查询, 响应缓存插件response cache plugin,和 RESTDataSource
)。 Apollo Server默认使用内存缓存,但您可以配置它使用不同的后端,例如Redis或Memcached。
您可以通过将 cache
选项传递给 ApolloServer
构造函数来指定缓存后端。您指定的缓存后端必须实现从 KeyValueCache
包中的 @apollo/utils.keyvaluecache
接口。
有很多缓存后端实现可供选择,包括Apollo提供的一些实现。例如,Apollo在 @apollo/utils.keyvaluecache
包中维护了一个 InMemoryLRUCache
的实现。Apollo还提供了一个包装类,名为 keyv
(实现了多个缓存后端),在 KeyvAdapter
包中。
配置内存缓存
⚠️ 如果您正在使用Apollo Server 3,请参阅 这篇文章的上一版本 了解如何使用有界缓存来保护您的缓存免受拒绝服务攻击。默认情况下,Apollo Server 4的默认缓存是一个 有界 的内存缓存后端。
您可以使用 cache
构造函数选项来配置服务器以使用不同的后端(例如Redis或Memcached)。
如果您想配置默认的内存缓存,Apollo提供了从 InMemoryLRUCache
类,该类来自 @apollo/utils.keyvaluecache
包。
“InMemoryLRUCache”类是对
lru-cache
包的封装,默认内存最大约为30MiB。您可以像配置lru-cache
包中的实例一样配置InMemoryLRUCache
的实例,有关详细信息,请参阅lru-cache
文档。您可以通过传递给ApolloServer
构造函数的cache
选项来使用Apollo的InMemoryLRUCache
类,如下所示:
import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';const server = new ApolloServer({cache: new InMemoryLRUCache(),});
在此示例中,我们增加了默认大小并提供了默认的TTL。有关这些配置选项的更多信息,请参阅lru-cache
文档。
import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';const server = new ApolloServer({// ...cache: new InMemoryLRUCache({// ~100MiBmaxSize: Math.pow(2, 20) * 100,// 5 minutes (in seconds)ttl: 300,}),});
配置外部缓存
Apollo不再直接维护任何缓存后端。相反,我们建议使用keyv
包,以及通过KeyvAdapter
类(由@apollo/utils.keyvadapter
包提供)。
KeyvAdapter
包裹了一个 Keyv
实例,实现了 Apollo Server 需要的 KeyValueCache
接口。您可以使用 KeyvAdapter
类来包装一个 Keyv
实例,并像这样将其提供给 ApolloServer
构造函数的 cache
选项:
- 安装所需的包
npm install keyv @apollo/utils.keyvadapter
- 配置 Apollo Server 的 Apollo Server
cache
import Keyv from 'keyv';import { KeyvAdapter } from '@apollo/utils.keyvadapter';const server = new ApolloServer({// ...,cache: new KeyvAdapter(new Keyv()),});
实现自己的缓存后端
如果您的需求是专业的或者您想实现自己的缓存后端,您可以实现 KeyValueCache
接口并将其直接传递给 ApolloServer
构造函数。
下面的 KeyValueCache
接口:
interface KeyValueCache<V> {get(key: string): Promise<V | undefined>;// ttl is specified in secondsset(key: string, value: V, options?: { ttl?: number | null }): Promise<void>;delete(key: string): Promise<boolean | void>;}
配置 Redis
The @keyv/redis
包使用底层的 ioredis
包。第二个选项参数通过传递给 ioredis.Redis
构造函数。请参阅 ioredis
文档以获取可用选项的列表。
首先安装所需的包
npm install keyv @keyv/redis @apollo/utils.keyvadapter
单个实例
import Keyv from "keyv";import { KeyvAdapter } from "@apollo/utils.keyvadapter";const server = new ApolloServer({typeDefs,resolvers,cache: new KeyvAdapter(new Keyv("redis://user:pass@localhost:6379")),});
Redis Sentinel
import Keyv from "keyv";import { KeyvAdapter } from "@apollo/utils.keyvadapter";const server = new ApolloServer({typeDefs,resolvers,cache: new KeyvAdapter(new Keyv("redis://user:pass@localhost:6379", {sentinels: [{ host: "localhost", port: 26379 },{ host: "localhost", port: 26380 },],})),});
Redis 集群
“@keyv/redis”@keyv/redis
包不支持直接使用 ioredis.Cluster
。相反,我们可以创建自己的 ioredis.Cluster
实例并将其作为对象传递给 keyv
作为存储对象。查看 ioredis.Cluster
文档 以获取可用选项列表。
首先安装我们需要的包
npm install keyv @keyv/redis ioredis @apollo/utils.keyvadapter
import Keyv from "keyv";import KeyvRedis from "@keyv/redis";import Redis from "ioredis";import { KeyvAdapter } from "@apollo/utils.keyvadapter";const cluster = new Redis.Cluster([{ host: "localhost", port: 26379 },{ host: "localhost", port: 26380 },]);const server = new ApolloServer({typeDefs,resolvers,cache: new KeyvAdapter(new Keyv({ store: new KeyvRedis(cluster) }), {disableBatchReads: true,}),});
注意 disableBatchReads
选项。这个选项禁用了批处理,而 ioredis.Cluster
不支持批处理。
配置Memcache
“@keyv/memcache”@keyv/memcache
包在底层使用了 memjs
包。其二选项 argument 传递给 memjs.Client.create()
。查看 memjs
文档 以获取可用选项列表。
首先安装所需的包
npm install keyv @keyv/memcache @apollo/utils.keyvadapter
import Keyv from "keyv";import KeyvMemcache from "@keyv/memcache";import { KeyvAdapter } from "@apollo/utils.keyvadapter";// servers is a comma-separated list of stringsconst servers = ["user:pass@localhost:11211","user:pass@localhost:11222"].join(",");const memcache = new KeyvMemcache(servers, {retries: 10,expires: 60,});const server = new ApolloServer({typeDefs,resolvers,cache: new KeyvAdapter(new Keyv({ store: memcache })),});
处理缓存获取错误
为了提供通过客户端(例如,Redis)连接的缓存后端容错,我们建议使用来自 @apollo/utils.keyvaluecache 的 ErrorsAreMissesCache
包装器。如果缓存不可用并且您的请求引发错误,ErrorsAreMissesCache
将该错误视为缓存未命中。同时,您的缓存客户端可以持续尝试重新连接到您的缓存后端,直到一切恢复正常,如下所示:
import Keyv from "keyv";import { KeyvAdapter } from "@apollo/utils.keyvadapter";import { ErrorsAreMissesCache } from "@apollo/utils.keyvaluecache";const redisCache = new Keyv("redis://user:pass@localhost:6379");const faultTolerantCache = new ErrorsAreMissesCache(new KeyvAdapter(redisCache),);
遗留缓存实现
Apollo Server 3.9 之前的版本使用 apollo-server-caching
包来实现缓存。由于 apollo-server-caching
包不再维护,我们不推荐使用它。
“KeyValueCache” 接口已移位,现位于
@apollo/utils.keyvaluecache
包中。
“InMemoryLRUCache” 类也已移至
@apollo/utils.keyvaluecache
包。现在的 InMemoryLRUCache
类使用版本 7 的 lru-cache
,接受不同的配置选项,不再允许缓存无限制。