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 一样的缓存应该在两个地方?

据我所知,传递给 ApolloServercache 严格用于 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 缓存都很有用,但方式截然不同。