适用于旧版捆绑服务的 Memcache API

本页面简要介绍了 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 免费
容量
us-central
1GB 到 100GB
其他地区
1GB 到 20GB
无保证容量
性能 每 GB 每秒最多 10000 次读取或 5000 次写入(独占)(内容 < 1KB)。如需了解详情,请参阅缓存统计信息 不保证
持久存储空间
服务等级协议

专用 Memcache 以 15 分钟为增量计费。如果您使用非美元货币付费,请参阅 Cloud Platform SKU 上以您的币种列出的价格。

如果您的应用需要更多 Memcache 容量,请联系我们的销售团队

限制

使用 Memcache 服务有以下限制:

  • 缓存数据值的大小上限为 1 MiB(2^20 个字节)减去键的大小以及与实现相关的开销(约为 73 个字节)。
  • 键不能大于 250 个字节。在 Java 运行时中,如果键是超过 250 个字节的对象或字符串,则将对它们进行哈希处理。(其他运行时的处理方式有所不同)。
  • “多”批量操作可以包含任意数量的元素。调用的总大小和提取数据的总大小不得超过 32 MB。
  • Memcache 键不能包含 null 字节。

可用的 API

App Engine Memcache 支持两种接口:低层级 Memcache API 和 JCache 规范。以下部分提供了有关每种接口的详细信息。

低层级 API

与 JCache 相比,低层级 Memcache API 支持更多功能。 例如:

  • 以原子方式递增和递减整数计数器值。
  • 显示更多缓存统计信息,例如距上次访问最近使用的条目以来的时间,以及缓存中所有项目的总大小。
  • 检查并设置操作以有条件地存储数据。
  • 使用 AsyncMemcacheService 异步执行 Memcache 操作。

低层级 API 提供 MemcacheServiceAsyncMemcacheService 以访问 Memcache 服务。此 API 比 JCache 提供的 API 功能更丰富。

有关低层级 Memcache API 的同步和异步使用示例,请参阅 Memcache 示例

JCache

App Engine Java SDK 支持 JCache API。JCache 为缓存的数据提供了类似于映射的接口。您可使用键将值存储在缓存中并从中检索值。键和值可以是任何可序列化类型或类。如需了解详情,请参阅使用 Memcache

不支持的 JCache 功能

JCache 不支持以下功能:

  • 对于可在处理应用的 API 调用期间执行的侦听器(例如 onPutonRemove 侦听器),目前还无法完全支持 JCache 侦听器 API。也不支持需要后台处理的侦听器(例如 onEvict)。
  • 应用程序可以测试缓存是否包含给定键,但不能测试缓存是否包含给定值(不支持 containsValue())。
  • 应用不能转储缓存的键或值的内容。
  • 应用不能手动重置缓存统计数据。
  • put() 方法不返回键的上一个已知值。它始终返回 null

缓存数据如何过期

Memcache 包含键值对。在缓存中写入和检索内容时,内存中的键值对随时会发生变化。

默认情况下,Memcache 中存储的值将保留尽可能长的时间。如果有新值添加到缓存中,而缓存内存不足,则系统可能会从缓存中逐出值。因内存压力而逐出值时,会先逐出最近最少使用的值。

在存储值时,应用可以提供以下形式的过期时间:从值添加时间起计算的秒数,或者将来的绝对 Unix 纪元时间(从 1970 年 1 月 1 日午夜算起的秒数)。值的逐出时间不会晚于过期时间,但也可能会因其他原因而提前逐出。增加为现有键存储的值不会更新其过期时间。

在极少数情况下,值也可能会因内存压力以外的原因而在过期之前从缓存中消失。虽然 Memcache 对于服务器故障具有很强的复原力,但 Memcache 值不会保存到磁盘,因此服务故障会导致值不可用。

一般来说,应用不应该期待缓存值始终可用。

您可以通过 API 或在 Google Cloud Console 的 Memcache 部分清空应用的整个缓存。

缓存统计信息

按内容大小的每秒操作次数

专用 Memcache 按每 GB 每秒操作次数确定操作速率,其中,一次操作的定义为访问一次个别缓存内容,例如 getsetdelete。操作速率因内容大小而异,大致如下表所示。如果超出这些速率,可能会导致 API 延迟时间延长或错误增加。

下表提供了每 GB 缓存的持续独占 get-hitset 操作次数上限。请注意,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 Console 会显示您的应用当前正在使用的 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 API 失败。Memcache 操作可能会因各种原因而失败。在设计应用时,应该让它们能够捕获失败的操作,而不是向最终用户显示这些错误。特别是在涉及 Set 操作时,更要注意这一点。

  • 尽量使用 API 的批处理功能,尤其是对于较小的内容。这样做可以提高应用的性能和效率。

  • 在整个 Memcache 键空间分配负载。如果单个或一小组 Memcache 内容占据了过大比例的流量,则会妨碍您的应用扩缩。这一指南同样适用于每秒操作次数和带宽。通常,您可以通过将数据明确分片来缓解此问题。

    例如,您可以在多个键之间拆分某个频繁更新的计数器,仅在您需要总计时才读回这些值并求和。同样,您可以在多个键之间拆分在执行每个 HTTP 请求时都必须读取的一片大小为 500K 的数据,并使用单个批量 API 调用读回这些值。(更好的方法是在实例内存中缓存该值。)对于专用 Memcache,单个键的峰值访问速率应该比每 GB 速率低 1-2 个数量级。

后续步骤