Skip to content

Commit

Permalink
Update caching docs (#6547)
Browse files Browse the repository at this point in the history
Add new page for configuring Apollo Server's cache. Include details on how to use
`InMemoryCache` as well as `Keyv` + `KeyvAdapter`. Add information about the
new `cache: "bounded"` option and the associated risks. Update other
cache-related docs to point to the new cache-backends page when appropriate.

Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
Co-authored-by: Stephen Barlow <stephen@apollographql.com>
  • Loading branch information
3 people committed Jun 15, 2022
1 parent b6fda1b commit 9387cba
Show file tree
Hide file tree
Showing 10 changed files with 1,088 additions and 854 deletions.
1 change: 1 addition & 0 deletions cspell-dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Loftis
loglevel
Luca
MAXAGE
memjs
mget
Mget
microrouter
Expand Down
5 changes: 3 additions & 2 deletions docs/source/api/apollo-server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ A key-value cache that Apollo Server uses to store previously encountered GraphQ

Whenever Apollo Server receives an incoming operation, it checks whether that exact operation is present in its `documentStore`. If it's present, Apollo Server can safely skip parsing and validating the operation, thereby improving performance.

The default `documentStore` is an [`InMemoryLRUCache`](https://github.com/apollographql/apollo-server/blob/main/packages/apollo-server-caching/src/InMemoryLRUCache.ts) with an approximate size of 30MiB. This is usually sufficient unless the server processes a large number of unique operations. Provide this option if you want to change the cache size or store the cache information in an alternate location.
The default `documentStore` is an [`InMemoryLRUCache`](https://github.com/apollographql/apollo-utils/blob/main/packages/keyValueCache/src/InMemoryLRUCache.ts) with an approximate size of 30MiB. This is usually sufficient unless the server processes a large number of unique operations. Provide this option if you want to change the cache size or store the cache information in an alternate location.

To use `InMemoryLRUCache` but change its size to an amount `approximateDocumentStoreMiB`:

Expand Down Expand Up @@ -244,7 +244,8 @@ By default, the cache is unbounded. We don't recommend this, since a malicious c

If you don't want to configure your own cache, you should set `cache: "bounded"`. The bounded cache is an [`InMemoryLRUCache`](https://www.npmjs.com/package/@apollo/utils.keyvaluecache) with a default size of roughly 30MiB.

FIXME: link to new cache backend page
To learn more about configuring Apollo Server's cache, see [Configuring cache backends](../performance/cache-backends).

</td>
</tr>

Expand Down
1 change: 1 addition & 0 deletions docs/source/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
},
"Performance": {
"Caching": "/performance/caching",
"Cache backends": "/performance/cache-backends",
"Automatic persisted queries": "/performance/apq"
},
"Security": {
Expand Down
59 changes: 5 additions & 54 deletions docs/source/data/data-sources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,66 +89,17 @@ const resolvers = {

## Caching

By default, data source implementations use Apollo Server's [`InMemoryLRUCache`](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/InMemoryLRUCache.ts#L14) to store the results of past fetches.
By default, data source implementations use Apollo Server's in-memory cache to store the results of past fetches.

When you initialize Apollo Server, you can provide its constructor a _different_ cache object that implements the [`KeyValueCache` interface](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/KeyValueCache.ts#L10-L14). This enables you to back your cache with shared stores like Memcached or Redis.
When you initialize Apollo Server, you can provide its constructor a _different_ cache object that implements the [`KeyValueCache` interface](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface). This enables you to back your cache with shared stores like Memcached or Redis.

### Using Memcached/Redis as a cache storage backend
### Using an external cache backend

When running multiple instances of your server, you should use a shared cache backend. This enables one server instance to use the cached result from _another_ instance.

Apollo Server supports using [Memcached](https://memcached.org/) or [Redis](https://redis.io/) as cache stores via the [`apollo-server-cache-memcached`](https://www.npmjs.com/package/apollo-server-cache-memcached) and [`apollo-server-cache-redis`](https://www.npmjs.com/package/apollo-server-cache-redis) packages. You can specify which one to use by creating an instance and passing it into the `ApolloServer` constructor.

#### Memcached

```js
const { MemcachedCache } = require('apollo-server-cache-memcached');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: new MemcachedCache(
['memcached-server-1', 'memcached-server-2', 'memcached-server-3'],
{ retries: 10, retry: 10000 }, // Options
),
dataSources: () => ({
moviesAPI: new MoviesAPI(),
}),
});
```

For the options you can pass to the underlying Memcached client, [see the documentation](https://github.com/3rd-Eden/memcached).

#### Redis

```js title="Redis"
const { BaseRedisCache } = require('apollo-server-cache-redis');
const Redis = require('ioredis');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: new BaseRedisCache({
client: new Redis({
host: 'redis-server',
}),
}),
dataSources: () => ({
moviesAPI: new MoviesAPI(),
}),
});
```

For the options you can pass to the underlying Redis client, [see the documentation](https://github.com/luin/ioredis).

### Implementing your own cache backend

You can create your own implementation of the [`KeyValueCache` interface](https://github.com/apollographql/apollo-server/blob/0aa0e4b20ef97576ce92733698a7842b61d8280e/packages/apollo-server-caching/src/KeyValueCache.ts#L10-L14) to connect to other caching data stores, or to optimize for your application's query characteristics.

For more information, see the README in for [apollo-server-caching](https://www.npmjs.com/package/apollo-server-caching).
Apollo Server supports using [Memcached](https://memcached.org/), [Redis](https://redis.io/), or other cache backends via the [`keyv`](https://www.npmjs.com/package/keyv) package. For examples, see [Configuring external caching](../performance/cache-backends#configuring-external-caching).

You can also choose to implement your own cache backend. For more information, see [Implementing your own cache backend](../performance/cache-backends#implementing-your-own-cache-backend).

## `RESTDataSource` reference

Expand Down
2 changes: 1 addition & 1 deletion docs/source/integrations/middleware.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ All Apollo Server packages depend on `apollo-server-core`, which contains the co

All Apollo Server packages (and `apollo-server-core`) are published to npm with the same version number, even if certain packages have no changes for a particular version. This makes it more straightforward to discuss a particular version of Apollo Server without needing to specify a package name.

Certain support libraries (such as `apollo-server-caching`, `apollo-server-types`, and `apollo-server-plugin-base`) use their own versioning and are published only when they change or one of their dependencies changes.
Certain support libraries (such as `apollo-server-types` and `apollo-server-plugin-base`) use their own versioning and are published only when they change or one of their dependencies changes.

### Common options

Expand Down
134 changes: 4 additions & 130 deletions docs/source/performance/apq.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,143 +182,17 @@ How exactly this works depends on exactly which CDN you chose. Configure your CD

By default, Apollo Server stores its APQ registry within its local in-memory cache. If you provide a different `cache` as a top-level option to the `ApolloServer` constructor, Apollo Server uses that cache instead.

You can also designate a cache _specifically_ for the APQ registry. To do so, provide an instance of your preferred cache class to the `ApolloServer` constructor as a `cache` option nested inside the `persistedQueries` options object. The following backing data stores are supported:
You can also designate a cache _specifically_ for the APQ registry. To do so, provide an instance of your preferred cache class to the `ApolloServer` constructor as a `cache` option nested within the `persistedQueries` options object. The `persistedQueries.cache` option is a [`KeyValueCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface), which accepts the same configuration options as Apollo Server's `cache` object (also a `KeyValueCache`).

| Data store | Class name | Library |
|---|---|---|
| Local in-memory cache (default) | `InMemoryLRUCache` | [`apollo-server-caching`](https://npm.im/apollo-server-caching) |
| Memcached | `MemcachedCache` | [`apollo-server-cache-memcached`](https://npm.im/apollo-server-cache-memcached) |
| Redis (single instance or Sentinel) | `RedisCache` | [`apollo-server-cache-redis`](https://npm.im/apollo-server-cache-redis) |
| Redis Cluster | `RedisClusterCache`| [`apollo-server-cache-redis`](https://npm.im/apollo-server-cache-redis)|

Examples for supported data stores are provided below.

### Memcached

```shell
$ npm install apollo-server-cache-memcached
```

```javascript
const { MemcachedCache } = require('apollo-server-cache-memcached');
const { ApolloServer } = require('apollo-server');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
// highlight-start
persistedQueries: {
cache: new MemcachedCache(
['memcached-1.local', 'memcached-2.local', 'memcached-3.local'],
{ retries: 10, retry: 10000 }, // Options
),
},
// highlight-end
});
```

### Redis (single instance)

```shell
$ npm install apollo-server-cache-redis ioredis
```

```javascript
const { BaseRedisCache } = require('apollo-server-cache-redis');
const Redis = require('ioredis');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
// highlight-start
persistedQueries: {
cache: new BaseRedisCache({
client: new Redis({
host: 'redis-server',
}),
}),
},
// highlight-end
});
```

### Redis (Sentinel)

```shell
$ npm install apollo-server-cache-redis ioredis
```

```javascript
const { BaseRedisCache } = require('apollo-server-cache-redis');
const Redis = require('ioredis');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
// highlight-start
persistedQueries: {
cache: new BaseRedisCache({
client: new Redis({
sentinels: [{
host: 'sentinel-host-01',
port: 26379
}],
password: 'my_password',
name: 'service_name',
}),
}),
},
// highlight-end
});
```

### Redis Cluster

```shell
$ npm install apollo-server-cache-redis ioredis
```

```javascript
const { BaseRedisCache } = require('apollo-server-cache-redis');
const Redis = require('ioredis');

const server = new ApolloServer({
typeDefs,
resolvers,
csrfPrevention: true,
cache: 'bounded',
// highlight-start
persistedQueries: {
cache: new BaseRedisCache({
// Note that this uses the "noMgetClient" option rather than "client",
// which avoids using the mget command which doesn't work in cluster mode.
noMgetClient: new Redis.Cluster(
[{
host: 'redis-node-01-host',
}],
{
// Other Redis cluster client options
}
),
}),
},
// highlight-end
});
```
To learn how to configure the in-memory cache, set up an external cache, or write your own cache implementation, see [Configuring cache backends](./cache-backends).

## Adjusting cache time-to-live (TTL)

The cache time-to-live (TTL) value determines how long a registered APQ remains in the cache. If a cached query's TTL elapses and the query is purged, it's re-registered the next time it's sent by a client.

Apollo Server's default in-memory store does not specify a TTL for APQ (an APQ remains cached until it is overwritten by the cache's standard eviction policy). For all other [supported stores](#cache-configuration), the default TTL is 300 seconds. You can override or disable this value by setting the `ttl` attribute of the `persistedQueries` option, in seconds:

```javascript
```ts
const server = new ApolloServer({
typeDefs,
resolvers,
Expand All @@ -334,7 +208,7 @@ const server = new ApolloServer({

To disable TTL entirely, specify `null` for the value of `ttl`:

```javascript
```ts
const server = new ApolloServer({
typeDefs,
resolvers,
Expand Down

0 comments on commit 9387cba

Please sign in to comment.