

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在中配置服务器端缓存和 API 有效负载压缩 AWS AppSync
<a name="enabling-caching"></a>

AWS AppSync的服务器端数据缓存功能在内存缓存中高速提供数据，从而提高性能并减少延迟。这减少了直接访问数据来源的需求。缓存适用于单位解析器和管道解析器。

AWS AppSync 还允许您压缩 API 响应，以便更快地加载和下载负载内容。这可能会减轻应用程序的压力，同时还可能会降低数据传输费用。压缩行为是可配置的，您可以自行决定进行设置。

有关在 AWS AppSync API 中定义服务器端缓存和压缩所需行为的帮助，请参阅本节。

## 实例类型
<a name="caching-instances"></a>

AWS AppSync 将亚马逊 ElastiCache (Redis OSS) 实例托管在与您的 AWS AppSync API 相同的 AWS 账户和 AWS 区域中。

有以下 ElastiCache （Redis OSS）实例类型可供选择：

**small**  
1 个 vCPU、1.5 GiB RAM、低到中网络性能

**medium**  
2 个 vCPU、3 GiB RAM、低到中网络性能

**large**  
2 个 vCPU、12.3 GiB RAM，高达 10 Gb 网络性能

**xlarge**  
4 个 vCPU、25.05 GiB RAM，高达 10 Gb 网络性能

**2xlarge**  
8 个 vCPU、50.47 GiB RAM，高达 10 Gb 网络性能

**4xlarge**  
16 个 vCPU、101.38 GiB RAM，高达 10 Gb 网络性能

**8xlarge**  
32 个 vCPU、203.26 GiB RAM、10 Gb 网络性能（并非在所有区域中都提供）

**12xlarge**  
48 个 vCPU、317.77 GiB RAM、10 Gb 网络性能

**注意**  
过去，您指定了特定的实例类型（例如 `t2.medium`）。自 2020 年 7 月起，这些旧实例类型可以继续使用，但将弃用这些实例类型而不建议使用。我们建议您使用此处描述的通用实例类型。

## 缓存行为
<a name="caching-behavior"></a>

以下是与缓存相关的行为：

**无**  
没有服务器端缓存。

**完整请求缓存**  
完全请求缓存是一种单独缓存解析器执行结果的机制。使用此设置， AWS AppSync 缓存请求期间调用的所有解析器的执行，每个解析器都单独缓存。每个解析器的数据都从其数据来源中检索并填入缓存，直到生存时间（TTL）到期。对于后续的 API 请求，会从缓存中返回每个特定解析器的结果。这意味着，除非TTL已过期，否则不会直接联系数据源。 AWS AppSync 使用`context.arguments`和`context.identity`映射的内容作为每个解析器的缓存密钥。

**每个解析器的缓存**  
对于该设置，必须明确选择每个解析器以缓存响应。您可以在解析器上指定 TTL 和缓存键。您可以指定的缓存键是这些地图中的顶级地图`context.arguments``context.source`、`context.identity`、和 and/or 字符串字段。TTL 值是必需的，但缓存键是可选的。如果您未指定任何缓存键，则默认值是 `context.arguments`、`context.source` 和 `context.identity` 映射内容。  
例如，您可以使用以下组合：  
+ *context.arguments* 和 *context.source*
+ *context.arguments* 和 *context.identity.sub*
+ *context.arguments.id 或上下文参数。* * InputType.id*
+ *context.source.id* 和 *context.identity.sub*
+ *context.identity.claims.username*
在您仅指定 TTL 而没有指定缓存键时，解析器的行为与完整请求缓存相同。

**操作级别缓存**  
操作级别缓存将整个 GraphQL 查询操作响应作为一个整体进行存储。启用后，系统会缓存成功的查询响应，直至其 TTL 到期，可缓存的最大响应大小为 15 MB。对于后续使用相同缓存键的查询请求，在 TTL 未过期之前，响应将直接从缓存中提供，而不会执行任何解析器。  
操作级别缓存的缓存键使用以下各项的组合生成：  
+ 请求的 JSON 有效载荷中的某些属性：
  + `query` 字符串
  + `operationName` 字符串
  + `variables` 映射
+ `context.identity` 映射（不包括 `context.identity.sourceIp` IAM 和 Amazon Cognito 请求）
+ `context.request.headers` 映射（不包括下一节中列出的某些保留标头） 
请求使用的授权类型也会影响缓存键。对于 IAM 授权的请求，缓存键还将包括允许和拒绝资源的列表。对于 Lambda 授权的请求，缓存键还将包括拒绝字段的列表。  
缓存键将考虑在 `context.request.headers` 中找到的所有请求标头，但以下保留标头除外，这些标头通常是特定请求所独有的：  
+ authorization
+ cloudfront-forwarded-proto
+ cloudfront-is-desktop-viewer
+ cloudfront-is-mobile-viewer
+ cloudfront-is-smarttv-viewer
+ cloudfront-is-tablet-viewer
+ cloudfront-viewer-asn
+ cloudfront-viewer-country
+ content-length
+ host
+ priority
+ sec-ch-ua
+ sec-ch-ua-mobile
+ sec-ch-ua-platform
+ via
+ x-amz-cf-id
+ x-amz-date
+ x-amz-security-token
+ x-amzn-appsync-is-vpce-request
+ x-amzn-remote-ip
+ x-amzn-requestid
+ x-amzn-trace-id
+ x-forwarded-for

**缓存生存时间**  
该设置定义在内存中存储缓存条目的时间。最大 TTL 为 3,600 秒（1 小时），之后自动删除条目。

## 缓存加密
<a name="caching-encryption"></a>

当您使用 AWS AppSync服务器端数据缓存功能时，静态和传输中的加密将始终为新缓存启用，并且无法禁用。

要对现有 API 缓存启用加密，请删除缓存，然后重新创建缓存。

要使缓存条目失效，您可以使用 AWS AppSync 控制台或 AWS Command Line Interface (AWS CLI) 进行刷新缓存 API 调用。

有关更多信息，请参阅 AWS AppSync API 参考中的[ApiCache](https://docs.aws.amazon.com/appsync/latest/APIReference/API_ApiCache.html)数据类型。

## 缓存逐出
<a name="cache-eviction-overview"></a>

设置 AWS AppSync服务器端缓存时，可以配置最大 TTL。该值定义在内存中存储缓存条目的时间。在必须从缓存中删除特定条目的情况下，可以在解析器的请求或响应中使用 AWS AppSync`evictFromApiCache`扩展实用程序。（例如，如果数据来源中的数据发生变化，并且缓存条目现已过时。） 要从缓存中逐出某个项目，您必须知道该项目的键。因此，如果您必须动态逐出项目，我们建议使用每个解析器的缓存，并明确定义一个用于将条目添加到缓存的键。

## 逐出缓存条目
<a name="evicting-cache-entries"></a>

要从缓存中逐出项目，请使用 `evictFromApiCache` 扩展实用程序。指定类型名称和字段名称，然后提供一个键值项目对象以构建要逐出的条目的键。在该对象中，每个键表示 `context` 对象中的一个有效条目，该条目在缓存解析器的 `cachingKey` 列表中使用。每个值是用于构建键值的实际值。您必须按照与缓存解析器的 `cachingKey` 列表中的缓存键相同的顺序，将项目放入对象中。

例如，请参阅以下架构：

```
type Note {
  id: ID!
  title: String
  content: String!
}

type Query {
  getNote(id: ID!): Note
}

type Mutation {
  updateNote(id: ID!, content: String!): Note
}
```

在该示例中，您可以启用每个解析器的缓存，然后为 `getNote` 查询启用该功能。接下来，您可以将缓存键配置为由 `[context.arguments.id]` 组成。

当你尝试获取 a 时`Note`，为了构建缓存密钥，使用`getNote`查询的`id`参数在其服务器端缓存中 AWS AppSync 执行查找。

在您更新 `Note` 时，您必须逐出特定注释的条目，以确保下一个请求从后端数据来源中获取该注释。为此，您必须创建一个请求处理程序。

以下示例说明了一种使用该方法处理逐出的方法：

```
import { util, Context } from '@aws-appsync/utils';
import { update } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	extensions.evictFromApiCache('Query', 'getNote', { 'ctx.args.id': ctx.args.id });
	return update({ key: { id: ctx.args.id }, update: { context: ctx.args.content } });
}

export const response = (ctx) => ctx.result;
```

或者，您也可以在响应处理程序中处理逐出。

处理`updateNote`突变后， AWS AppSync 会尝试驱逐该条目。如果成功清除条目，响应将在 `extensions` 对象中包含一个 `apiCacheEntriesDeleted` 值，以显示删除的条目数：

```
"extensions": {  "apiCacheEntriesDeleted": 1}
```

## 根据身份逐出缓存条目
<a name="evicting-cache-identity"></a>

您可以根据 `context` 对象中的多个值创建缓存键。

例如，采用以下架构，该架构将 Amazon Cognito 用户池作为默认身份验证模式并由 Amazon DynamoDB 数据来源提供支持：

```
type Note {
  id: ID! # a slug; e.g.: "my-first-note-on-graphql"
  title: String
  content: String!
}

type Query {
  getNote(id: ID!): Note
}

type Mutation {
  updateNote(id: ID!, content: String!): Note
}
```

`Note` 对象类型保存在 DynamoDB 表中。该表具有一个组合键，该组合键将 Amazon Cognito 用户名作为主键，并将 `Note` 的 `id`（短标签）作为分区键。这是一个多租户系统，允许多个用户托管和更新他们的私有 `Note` 对象，这些对象从不进行共享。

由于这是一个读取密集型系统，因此，`getNote` 查询使用每个解析器的缓存进行缓存，缓存键由 `[context.identity.username, context.arguments.id]` 组成。在更新 `Note` 后，您可以逐出该特定 `Note` 的条目。您必须按照解析器的 `cachingKeys` 列表中指定的相同顺序将组件添加到对象中。

以下示例说明了这一点：

```
import { util, Context } from '@aws-appsync/utils';
import { update } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	extensions.evictFromApiCache('Query', 'getNote', {
		'ctx.identity.username': ctx.identity.username,
		'ctx.args.id': ctx.args.id,
	});
	return update({ key: { id: ctx.args.id }, update: { context: ctx.args.content } });
}

export const response = (ctx) => ctx.result;
```

后端系统也可以更新 `Note` 并逐出条目。例如，采用以下变更：

```
type Mutation {
  updateNoteFromBackend(id: ID!, content: String!, username: ID!): Note @aws_iam
}
```

您可以逐出条目，但将缓存键的组件添加到 `cachingKeys` 对象中。

在以下示例中，逐出是在解析器响应中进行的：

```
import { util, Context } from '@aws-appsync/utils';
import { update } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
    return update({ key: { id: ctx.args.id }, update: { context: ctx.args.content } });
}

export function response(ctx) {
    extensions.evictFromApiCache('Query', 'getNote', {
        'ctx.identity.username': ctx.args.username,
        'ctx.args.id': ctx.args.id,
    });
    return ctx.result;
}
```

如果您的后端数据已在外部更新 AWS AppSync，则可以通过调用使用`NONE`数据源的突变将项目从缓存中移出。

## 压缩 API 响应
<a name="api-response-compression"></a>

AWS AppSync 允许客户端请求压缩的有效负载。如果请求，将压缩并返回 API 响应，以响应指示希望压缩内容的请求。压缩的 API 响应加载速度更快，内容下载速度更快，并且您的数据传输费用也可能会下降。

**注意**  
2020 年 6 月 1 日之后 APIs 创建的所有新版本均可进行压缩。  
AWS AppSync 尽力[压缩](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html#compressed-content-cloudfront-notes)对象。在极少数情况下， AWS AppSync 可能会根据各种因素（包括当前容量）跳过压缩。

AWS AppSync 可以将 GraphQL 查询有效负载大小压缩在 1,000 到 1000 万字节之间。要启用压缩，客户端必须发送具有 `gzip` 值的 `Accept-Encoding` 标头。可以检查响应 (`gzip`) 中的 `Content-Encoding` 标头值以验证压缩。

默认情况下， AWS AppSync 控制台中的查询浏览器会自动在请求中设置标头值。如果您执行的查询具有足够大的响应，可以使用浏览器开发人员工具确认压缩。