本页面简要介绍了 App Engine memcache 服务。在执行某些任务时,高性能的可扩缩 Web 应用通常先使用分布式内存中的数据缓存,然后才使用或完全不使用可靠的永久存储空间。为此,App Engine 提供了内存缓存服务。如需了解如何配置、监控和使用 Memcache 服务,请阅读使用 Memcache。
何时使用内存缓存
内存缓存的一个用途是加快常见数据存储区查询的速度。如果许多请求使用相同的参数执行同一查询,并且结果更改不需要立即显示在网站上,则应用可以将结果缓存在 Memcache 中。后续请求可以直接检查 Memcache,只有在结果缺失或过期时才需要执行数据存储区查询。会话数据、用户偏好设置以及网页查询返回的其他数据都非常适合进行缓存。
Memcache 还可用于存储其他临时值。不过,在考虑是否仅在 Memcache 中存储值而不在其他永久存储空间中进行备份时,应确保在值突然变得不可用时,您的应用仍能以可接受的行为正常运作。值在 Memcache 中可能随时失效,可能会在为值设置的失效截止期限之前就已失效。例如,如果用户会话数据突然缺失会导致会话出现故障,则应考虑除了在 Memcache 中存储该数据之外,可能还应将其存储在数据存储区中。
服务等级
App Engine 支持两种 Memcache 服务等级:
共享 Memcache 是 App Engine 应用的免费默认等级。该服务等级会尽可能多地提供缓存容量,但会受限于使用此共享 Memcache 服务的所有 App Engine 应用的总体需求。
专用 Memcache 提供专为您的应用分配的固定缓存容量。该服务等级按缓存大小(GB 小时)计费,并要求启用结算功能。能够控制缓存的大小,意味着应用能够以更可预测的方式执行操作,同时减少更昂贵的持久存储空间的读取次数。
这两种 Memcache 服务等级都使用同一 API。如需为应用配置 Memcache 服务,请参阅使用 Memcache。
下表总结了这两种 Memcache 服务等级之间的区别:
功能 | 专用 Memcache | 共享 Memcache |
---|---|---|
价格 | 每 GB 每小时 $0.06 | 免费 |
容量 |
|
无保证容量 |
性能 | 每 GB 每秒最多 10000 次读取或 5000 次写入(独占)(内容 < 1KB)。如需了解详情,请参阅缓存统计信息。 | 不保证 |
持久存储空间 | 否 | 否 |
SLA | 无 | 无 |
专用 Memcache 以 15 分钟为增量计费。如果您使用非美元货币付费,请参阅 Cloud Platform SKU 上以您的币种列出的价格。
如果您的应用需要更多 Memcache 容量,请联系我们的销售团队。
限制
使用 Memcache 服务有以下限制:
- 缓存数据值的大小上限为 1 MB(10^6 个字节)。
- 键不能大于 250 个字节。 在 Python 运行时中,字符串长度超过 250 个字节的键将进行哈希处理。
- “多”批量操作可以包含任意数量的元素。调用的总大小和提取数据的总大小不得超过 32 MB。
- Memcache 键不能包含 null 字节。
建议和最佳实践
使用 Memcache 时,我们建议您将应用设计为:
处理缓存值不始终可用的情况。
- Memcache 不属于持久性存储服务。根据逐出政策,缓存被填满时会逐出键。缓存配置更改或数据中心维护事件也会清空部分或全部缓存。
- Memcache 可能会遇到暂时无法使用的情况。Memcache 操作可能会因各种原因而失败,包括缓存配置更改或数据中心维护事件。在设计应用时,应该让它们能够捕获失败的操作,而不是向最终用户显示这些错误。这一指导尤其适用于 Set 操作。
尽量使用 API 的批处理功能。
- 这样做可以提高应用的性能和效率,尤其是对于较小项。
在整个 Memcache 键空间分配负载。
如果单个或一小组 memcache 项占据了不成比例的流量,则会妨碍您的应用扩缩。这一指导对每秒操作次数和带宽均适用。通常,您可以通过明确对数据进行分片来缓解此问题。
例如,您可以在多个键之间拆分频繁更新的计数器,仅在您需要总计时才重新读取这些数据并求和。同样,您可以在多个键之间拆分必须对每个 HTTP 请求读取的一段 500K 数据,并使用单个批量 API 调用重新读取这些数据。(更好的方法是在实例内存中缓存该值。)对于专用 memcache,单个键的峰值访问速率应该比每 GB 速率低 1-2 个数量级。
保留您自己的键,以便从缓存中检索值。
- Memcache 不提供列出键的方法。缓存的性质决定了不能在不中断缓存的情况下列出键。此外,某些语言(如 Python)、哈希长键和原始键仅对应用已知。
缓存数据如何过期
Memcache 包含键值对。在缓存中写入和检索内容时,内存中的键值对随时会发生变化。
默认情况下,Memcache 中存储的值将保留尽可能长的时间。如果有新值添加到缓存中,而缓存内存不足,则系统可能会从缓存中逐出值。因内存压力而逐出值时,会先逐出最近最少使用的值。
在存储值时,应用可以提供以下形式的过期时间:从值添加时间起计算的秒数,或者将来的绝对 Unix 纪元时间(从 1970 年 1 月 1 日午夜算起的秒数)。值的逐出时间不会晚于过期时间,但也可能会因其他原因而提前逐出。增加为现有键存储的值不会更新其过期时间。
在极少数情况下,值也可能会因内存压力以外的原因而在过期之前从缓存中消失。虽然 Memcache 对于服务器故障具有很强的复原力,但 Memcache 值不会保存到磁盘,因此服务故障会导致值不可用。
一般来说,应用不应该期待缓存值始终可用。
您可以通过 API 或在 Google Cloud 控制台的 Memcache 部分清空应用的整个缓存。
缓存统计信息
按内容大小的每秒操作次数
专用 Memcache 按每 GB 每秒操作次数确定操作速率,其中,一次操作的定义为访问一次个别缓存内容,例如 get
、set
或 delete
。操作速率因内容大小而异,大致如下表所示。如果超出这些速率,可能会导致 API 延迟时间延长或错误增加。
下表提供了每 GB 缓存的持续独占 get-hit
或 set
操作次数上限。请注意,get-hit
操作是一种 get
调用,该调用会查找与指定键一起存储的值并返回该值。
内容大小 (KB) | 每秒 get-hit 操作次数上限 |
每秒 set 操作次数上限 |
---|---|---|
≤1 | 10000 | 5000 |
100 | 2000 | 1000 |
512 | 500 | 250 |
理论上,配置了多个 GB 缓存的应用可达到聚合操作速率,即为 GB 数乘以每 GB 速率得出的总速率。例如,对于 1KB 内容,配置了 5GB 缓存的应用可达到每秒 50000 次 Memcache 操作。需要在 Memcache 键空间合理分配负载,才能达到这一水平。
对于每种 IO 模式,上面列出的限制适用于读取或写入。对于同时读取和写入,限制按比例增减。执行的读取次数越多,可执行的写入次数就越少,反之亦然。下面列出了每 1GB 缓存同时读取和写入 1KB 值的 IOPS 限制示例:
读取 IOPS | 写入 IOPS |
---|---|
10000 | 0 |
8000 | 1000 |
5000 | 2500 |
1000 | 4500 |
0 | 5000 |
Memcache 计算单元 (MCU)
Memcache 吞吐量因您访问的内容大小以及您要对该内容执行的操作而异。大致来说,费用与操作次数相关联。您可以使用 Memcache 计算单元 (MCU) 估算专用 Memcache 预期可提供的流量容量。MCU 的定义如下:对于专用 Memcache,预期可提供每 GB 每秒 10000 个 MCU。Google Cloud 控制台会显示您的应用当前正在使用的 MCU 数量。
请注意,MCU 是大致的统计估算,而且它不是线性单元。每个读取或写入值的缓存操作具有相应的 MCU 费用,此费用取决于该值的大小。set
的 MCU 取决于值的大小:其费用是成功执行 get-hit
操作所需费用的 2 倍。
值内容大小 (KB) | get-hit 的 MCU 费用 |
set 的 MCU 费用 |
---|---|---|
≤1 | 1.0 | 2.0 |
2 | 1.3 | 2.6 |
10 | 1.7 | 3.4 |
100 | 5.0 | 10.0 |
512 | 20.0 | 40.0 |
1024 | 50.0 | 100.0 |
不读取或写入值的操作其 MCU 费用是固定的:
操作 | MCU |
---|---|
get-miss |
1.0 |
delete |
2.0 |
increment |
2.0 |
flush |
100.0 |
stats |
100.0 |
请注意,get-miss
操作是一种 get
调用,该调用发现没有针对特定键存储的值。
比较和设置
比较和设置功能允许并发处理的多个请求以原子方式更新同一 Memcache 键的值,从而避免出现争用情况。
比较和设置的关键逻辑组件
如果要更新可能会收到其他并发写入请求的 Memcache 键值,您必须使用 Memcache Client
对象,该对象可存储支持比较和设置功能的方法所使用的特定状态信息。您不能使用 Memcache 函数 get()
或 set()
,因为它们是无状态的。Client
类本身不是线程安全的,因此您不应在多个线程中使用同一 Client
对象。
检索键时,您必须使用支持比较和设置功能的 Memcache Client
方法:gets()
或 get_multi()
,并将 for_cas
参数设置为 True
。
更新键时,您必须使用支持比较和设置功能的 Memcache Client
方法:cas()
或 cas_multi()
。
另一个关键逻辑组件是 App Engine memcache 服务及其关于比较和设置的行为。App Engine memcache 服务本身以原子方式表现。也就是说,当两个并发请求(针对同一个应用 ID)使用 memcache 时,它们将转到相同的 memcache 服务实例,并且该 memcache 服务具有足够的内部锁定,这样对同一个键的并发请求就可以正确序列化。特别是,这意味着对同一个键的两个 cas()
请求实际上不会并行运行 - 服务先处理传入的第一个请求,完成后(即更新值和时间戳)才会开始处理第二个请求。
如需了解如何在 Python 中使用比较和设置,请阅读处理并发写入。
后续步骤
- 在使用 Memcache 中了解如何配置、监控和使用 Memcache。
- 浏览 Memcache 示例。