Memcache 概览

本页面简要介绍了 App Engine memcache 服务。通常,高性能的可扩展网络应用在可靠持久性存储之前使用分布式内存中数据缓存来执行某些任务,或者使用分布式内存中数据缓存替代可靠持久性存储来执行某些任务。为此,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
1 到 100GB
其他区域
1 到 20GB
无保证容量
性能 每 GB 每秒最多 10000 次读取或 5000 次写入(独占)(内容 < 1KB)。如需了解详情,请参阅缓存统计信息 不保证
持久性存储区 不支持 不支持
服务等级协议

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

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

限制

使用 memcache 服务应遵循以下限制:

  • 缓存数据值的大小上限为 1 MB(10^6 个字节)。
  • 键不能大于 250 个字节。在 Python 运行时中,字符串长度超过 250 个字节的键将进行哈希处理。(在其他运行时中,行为有所不同。)
  • “多”批量操作可以包含任意数量的元素。调用的总大小和已提取数据的总大小不得超过 32 MB。
  • Memcache 键不能包含 null 字节。

缓存数据如何过期

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

默认情况下,memcache 中存储的值将保留尽可能长的时间。如果在缓存中添加新值,且缓存内存不足,则可以从缓存中逐出值。由于内存压力而逐出值时,先逐出最近最少使用的值。

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

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

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

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

缓存统计信息

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

专用 memcache 按照每 GB 每秒操作次数计算速率,其中,操作定义为访问缓存内容一次,如 getsetdelete。根据下表,操作速率大致因内容大小而异。如果超出这些速率,则可能会导致 API 延迟时间延长或错误增加。

下表提供了每 GB 缓存的持续独占 get-hitset 操作次数上限。请注意,get-hit 操作等效于发现使用指定键进行存储的值并返回该值的 get 操作。

内容大小 (KB) 每秒 get-hit 操作次数上限 每秒 set 操作次数上限
≤1 10,000 5,000
100 2,000 1,000
512 500 250

理论上,配置为多 GB 缓存的应用可实现聚合操作速率,其计算方法为 GB 数乘以每 GB 速率。例如,在 1KB 内容上,配置为 5GB 缓存的应用可达到每秒 50,000 次 memcache 操作。如 App Engine 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 的定义使得每 GB 专用 memcache 每秒可以达到 10,000 个 MCU。Google Cloud Platform 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 键可能会接受其他并发写入请求,而您正在更新该键的值,则您必须使用 memcache Client 对象,该对象可存储支持比较和设置功能的方法所使用的特定状态信息。您不能使用 memcache 函数 get()set(),因为它们是无状态的。Client 类本身并非线程安全,因此您不应该在多个线程中使用同一个 Client 对象。

检索键时,您必须使用支持比较和设置功能的 memcache Client 方法:for_cas 参数设置为 Truegets()get_multi()

更新键时,您必须使用支持比较和设置功能的 memcache Client 方法:cas()cas_multi()

另一个关键逻辑组件是 App Engine memcache 服务及其关于比较和设置的行为。App Engine memcache 服务本身以原子方式表现。也就是说,当两个并发请求(针对同一个应用 ID)使用 memcache 时,它们将转到相同的 memcache 服务实例,并且该 memcache 服务具有足够的内部锁定,这样对同一个键的并发请求就可以正确序列化。特别是,这意味着对同一个键的两个 cas() 请求实际上不会并行运行 - 服务先处理传入的第一个请求,完成后(即更新值和时间戳)才会开始处理第二个请求。

如需了解如何在 Python 中使用比较和设置,请阅读处理并发写入

最佳做法

以下是使用 memcache 的一些最佳做法:

  • 正常处理 memcache API 失败。 Memcache 操作可能会因不同原因而失败。应用应该设计为捕捉失败的操作,而不将这些错误向最终用户公开。本指南特别适用于 Set 操作。

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

  • 在 memcache 键空间分配负载。 具有一组或一小组 memcache 内容表示不成比例的流量将阻碍您的应用扩缩。本指南适用于每秒操作次数和带宽。通常,您可以通过将数据明确分片来缓解此问题。

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

如需了解并发、性能以及迁移的更多详细信息和更多最佳做法,包括在不同编程语言之间共享 memcache,请阅读 App Engine Memcache 最佳做法一文。

后续步骤

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
App Engine standard environment for Python 2