Apollo服务器-关于缓存/数据源选项的困惑[英] Apollo Server - Confusion about cache/datasource options

本文是小编为大家收集整理的关于Apollo服务器-关于缓存/数据源选项的困惑的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

docs( https://www.colographqql.com/docs/apollo-server/features/data-sources.html#using-memached-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缓存应该是来自服务器缓存的不同缓存,也是应该在两个地方都有相同的缓存?

cache传递给ApolloServer是我的知识,严格使用在RESTDataSource的上下文中.从REST端点获取资源时,服务器将在响应上检查Cache-Control标题,如果存在一个,则将适当地缓存资源.这意味着如果标题是max-age=86400,则将通过24小时的TTL缓存响应,直到缓存条目到期,它将被使用,而不是调用相同的REST URL.

这与您实现的缓存机制不同,因为您的代码高速缓存数据库的响应.他们的意图是一样的,但他们与不同的资源合作.您的代码将有效复制apolloserver的cache已完成的唯一方法是如果您为REST端点写了类似的DataSource.

虽然这两个缓存减少了处理GraphQL响应所需的时间(从缓存中取出明显比从数据库中快速),客户端缓存会减少必须对服务器进行的请求数.最值得注意的是,InMemoryCache允许您在站点中的不同位置(如反应中的不同组件)中重复使用一个查询,同时仅获取查询一次.

因为客户端缓存是归一化的,它也意味着如果在通过一个查询获取时已经缓存了资源,则可能避免在用另一个查询请求时将其重新取消.例如,如果使用一个查询然后使用另一个查询获取用户列表,然后使用其他查询获取用户,则可以将客户端配置为查找缓存中的用户而不是制作第二个查询.

很重要的是要注意,虽然资源缓存的服务器端通常具有TTL,但InMemoryCache没有.相反,它使用"获取策略"来确定各个查询的行为.这使您可以让您具有始终从服务器获取的查询,而不管缓存中的内容如何.

希望有助于说明服务器端和客户端缓存都很有用,但以非常不同的方式.

本文地址:https://www.itbaoku.cn/post/1938050.html

问题描述

The docs (https://www.apollographql.com/docs/apollo-server/features/data-sources.html#Using-Memcached-Redis-as-a-cache-storage-backend) show code like this:

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(),
  }),
});

I was wondering how that cache key is used, considering it seems like the caching is actually custom implemented in something like MoviesAPI() and then used via context.dataSources.moviesAPI.someFunc(). For example, say I wanted to implement my own cache for a SQL database. It'd look like

  cache: new RedisCache({
    host: 'redis-server',
  }),
  dataSources: () => ({
    SQL: new SQLCache(),
  }),
});

where SQLCache has my own function that connects to the RedisCache like:

  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);
      });
    });
  }

So that means I have RedisCache in both the ApolloServer cache key and dataSource implementation. Clearly, the RedisCache is used in the dataSource implementation, but then what does that ApolloServer cache key do exactly?

Also on the client, examples mostly show use of InMemoryCache instead of Redis cache. Should the client Apollo cache be a different cache from the server cache or should the same cache like RedisCache be in both places?

推荐答案

The cache passed to the ApolloServer is, to my knowledge, strictly used in the context of a RESTDataSource. When fetching resources from the REST endpoint, the server will examine the Cache-Control header on the response, and if one exists, will cache the resource appropriately. That means if the header is max-age=86400, the response will be cached with a TTL of 24 hours, and until the cache entry expires, it will be used instead of calling the same REST url.

This is different than the caching mechanism you've implemented, since your code caches the response from the database. Their intent is the same, but they work with different resources. The only way your code would effectively duplicate what ApolloServer's cache already does is if you had written a similar DataSource for a REST endpoint instead.

While both of these caches reduce the time it takes to process your GraphQL response (fetching from cache is noticeably faster than from the database), client-side caching reduces the number of requests that have to be made to your server. Most notably, the InMemoryCache lets you reuse one query across different places in your site (like different components in React) while only fetching the query once.

Because the client-side cache is normalized, it also means if a resource is already cached when fetched through one query, you can potentially avoid refetching it when it's requested with another query. For example, if you fetch a list of Users with one query and then fetch a user with another query, your client can be configured to look for the user in the cache instead of making the second query.

It's important to note that while resources cached server-side typically have a TTL, the InMemoryCache does not. Instead, it uses "fetch policies" to determine the behavior of individual queries. This lets you, for example, have a query that always fetches from the server, regardless of what's in the cache.

Hopefully that helps to illustrate that both server-side and client-side caching are useful but in very different ways.