Apollo 服务器 - 关于 cache/datasource 选项的混淆
Apollo Server - Confusion about cache/datasource options
文档 (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
一样的缓存应该在两个地方?
据我所知,传递给 ApolloServer
的 cache
严格用于 RESTDataSource
的上下文中。从 REST 端点获取资源时,服务器将检查响应中的 Cache-Control
header,如果存在,将适当地缓存资源。这意味着如果 header 是 max-age=86400
,响应将以 24 小时的 TTL 缓存,并且在缓存条目过期之前,将使用它而不是调用相同的 REST url .
这与您实施的缓存机制不同,因为您的代码缓存了来自数据库的响应。他们的意图相同,但他们使用不同的资源。您的代码有效复制 ApolloServer 的 cache
已经做的事情的唯一方法是,如果您已经为 REST 端点编写了类似的 DataSource
。
虽然这两种缓存都减少了处理 GraphQL 响应所需的时间(从缓存中获取数据明显快于从数据库中获取数据),但 client-side 缓存减少了必须向你的服务器。最值得注意的是,InMemoryCache
允许您在网站的不同位置重复使用一个查询(就像 React 中的不同组件),而只获取一次查询。
因为 client-side 缓存是规范化的,这也意味着如果通过一个查询获取资源时已经缓存了资源,您可以避免在使用另一个查询请求时重新获取它。例如,如果您使用一个查询获取用户列表,然后使用另一个查询获取用户,您的客户端可以配置为在缓存中查找用户,而不是进行第二个查询。
请务必注意,虽然缓存的资源 server-side 通常具有 TTL,但 InMemoryCache
没有。相反,它使用 "fetch policies" 来确定单个查询的行为。例如,这可以让您有一个 总是 从服务器获取的查询,而不管缓存中有什么。
希望这有助于说明 server-side 和 client-side 缓存都很有用,但方式截然不同。
文档 (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
一样的缓存应该在两个地方?
据我所知,传递给 ApolloServer
的 cache
严格用于 RESTDataSource
的上下文中。从 REST 端点获取资源时,服务器将检查响应中的 Cache-Control
header,如果存在,将适当地缓存资源。这意味着如果 header 是 max-age=86400
,响应将以 24 小时的 TTL 缓存,并且在缓存条目过期之前,将使用它而不是调用相同的 REST url .
这与您实施的缓存机制不同,因为您的代码缓存了来自数据库的响应。他们的意图相同,但他们使用不同的资源。您的代码有效复制 ApolloServer 的 cache
已经做的事情的唯一方法是,如果您已经为 REST 端点编写了类似的 DataSource
。
虽然这两种缓存都减少了处理 GraphQL 响应所需的时间(从缓存中获取数据明显快于从数据库中获取数据),但 client-side 缓存减少了必须向你的服务器。最值得注意的是,InMemoryCache
允许您在网站的不同位置重复使用一个查询(就像 React 中的不同组件),而只获取一次查询。
因为 client-side 缓存是规范化的,这也意味着如果通过一个查询获取资源时已经缓存了资源,您可以避免在使用另一个查询请求时重新获取它。例如,如果您使用一个查询获取用户列表,然后使用另一个查询获取用户,您的客户端可以配置为在缓存中查找用户,而不是进行第二个查询。
请务必注意,虽然缓存的资源 server-side 通常具有 TTL,但 InMemoryCache
没有。相反,它使用 "fetch policies" 来确定单个查询的行为。例如,这可以让您有一个 总是 从服务器获取的查询,而不管缓存中有什么。
希望这有助于说明 server-side 和 client-side 缓存都很有用,但方式截然不同。