Apollo Server - 关于缓存/数据源选项的困惑
Posted
技术标签:
【中文标题】Apollo Server - 关于缓存/数据源选项的困惑【英文标题】:Apollo Server - Confusion about cache/datasource options 【发布时间】:2019-04-20 20:34:27 【问题描述】:文档 (https://www.apollographql.com/docs/apollo-server/features/data-sources.html#Using-Memcached-Redis-as-a-cache-storage-backend) 显示如下代码:
const RedisCache = require('apollo-server-cache-redis');
const server = new ApolloServer(
typeDefs,
resolvers,
cache: new RedisCache(
host: 'redis-server',
// Options are passed through to the Redis client
),
dataSources: () => (
moviesAPI: new MoviesAPI(),
),
);
我想知道cache
键是如何使用的,考虑到缓存似乎实际上是在MoviesAPI()
之类的东西中自定义实现的,然后通过context.dataSources.moviesAPI.someFunc()
使用。例如,假设我想为 SQL 数据库实现自己的缓存。它看起来像
cache: new RedisCache(
host: 'redis-server',
),
dataSources: () => (
SQL: new SQLCache(),
),
);
SQLCache
有我自己的函数连接到RedisCache
,例如:
getCached(id, query, ttl)
const cacheKey = `sqlcache:$id`;
return redisCache.get(cacheKey).then(entry =>
if (entry)
console.log('CACHE HIT!');
return Promise.resolve(JSON.parse(entry));
console.log('CACHE MISS!');
return query.then(rows =>
if (rows) redisCache.set(cacheKey, JSON.stringify(rows), ttl);
return Promise.resolve(rows);
);
);
这意味着我在ApolloServer
cache
键和dataSource
实现中都有RedisCache
。显然,RedisCache
用于 dataSource
实现中,但是 ApolloServer
cache
键到底是做什么的?
同样在客户端,示例大多显示使用 InMemoryCache
而不是 Redis 缓存。客户端 Apollo 缓存应该是与服务器缓存不同的缓存,还是应该在两个地方都使用像 RedisCache
这样的相同缓存?
【问题讨论】:
【参考方案1】:据我所知,传递给ApolloServer
的cache
严格用于RESTDataSource
的上下文中。从 REST 端点获取资源时,服务器将检查响应中的 Cache-Control
标头,如果存在,将适当地缓存资源。这意味着如果标头为max-age=86400
,则响应将以 24 小时的 TTL 缓存,并且在缓存条目过期之前,将使用它而不是调用相同的 REST url。
这与您实现的缓存机制不同,因为您的代码会缓存来自数据库的响应。他们的意图是相同的,但他们使用不同的资源。您的代码有效复制 ApolloServer 的 cache
已经做的唯一方法是,如果您为 REST 端点编写了类似的 DataSource
。
虽然这两种缓存都减少了处理 GraphQL 响应所需的时间(从缓存中获取明显快于从数据库中获取),但客户端缓存减少了必须向服务器发出的请求数量。最值得注意的是,InMemoryCache
允许您在站点的不同位置(如 React 中的不同组件)重复使用一个查询,同时只获取一次查询。
因为客户端缓存是规范化的,这也意味着如果通过一个查询获取资源时已经缓存了资源,您可以避免在通过另一个查询请求它时重新获取它。例如,如果您使用一个查询获取用户列表,然后使用另一个查询获取用户,则您的客户端可以配置为在缓存中查找用户,而不是进行第二次查询。
请务必注意,虽然服务器端缓存的资源通常具有 TTL,但 InMemoryCache
却没有。相反,它使用“获取策略”来确定单个查询的行为。例如,这使您可以拥有一个始终从服务器获取的查询,而不管缓存中有什么。
希望这有助于说明服务器端和客户端缓存都是有用的,但方式却截然不同。
【讨论】:
感谢您清晰的解释!仔细看看MoviesAPI
,它实际上并没有像我的SQLCache
那样实现自定义缓存,但似乎使用了扩展RESTDataSource
的辅助方法,所以像你说的那样有道理,它知道使用@987654334 @ 传递到 ApolloServer
。在那种情况下,我也觉得cache
真的应该被称为restCache
以避免混淆哈哈,但是哦,好吧。确实,我已经看到了即时客户端缓存的好处,但是由于您的帮助,我现在更好地理解了服务器端缓存的差异和目的!干杯!
我同意,这有点令人困惑并且没有很好的记录。我相信apollo-datasource
和apollo-link-state
一样仍在积极开发中。因此,FWIW,这些 API 在未来可能会发生变化。
嘿,好久不见!因此,功能越多,混乱就越多。这似乎超过了RESTDataSource
缓存的级别,并且更接近我最初想要的:apollographql.com/docs/apollo-server/features/caching/…,但仍然与“缓存来自数据库的响应”不太一样?你能评论一下新功能吗? :P 我认为它可能会起作用,因为我的解析器只是在它们前面使用缓存进行数据库调用,所以这似乎允许我将缓存放在整个服务器级别而不是每个解析器上?
如果您需要覆盖上游 TTL 值,您可以通过 RESTDataSource
中的以下方法来实现:willSendRequest(request: RequestOptions) request.cacheOptions = ttl: 3600 // 1h
以上是关于Apollo Server - 关于缓存/数据源选项的困惑的主要内容,如果未能解决你的问题,请参考以下文章
Apollo Server Lambda - 关于无服务器的任何实际示例