

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

# 设计注意事项
<a name="design"></a>

其他需要考虑的设计要点：
+ **错误处理**：如果缓存由于任何原因变得不可用，则应用程序应像所有项目都缺少缓存一样继续运行。缓存层的存在不应增加应用程序的脆弱性。
+ **TTL**：可以为所有缓存条目配置单个 TTL 值，也可以根据条目使用不同的 TTL 值（例如`get_item``query`、或`scan`缓存）。对于负缓存条目（未返回任何项目的请求），也可以使用不同的 TTL 值。
+ **已消耗的容量**：当您返回缓存的响应时，我们建议您调整响应中的`ConsumedCapacity`指标以表明读取消耗量为零。
+ **删除响应元数据**：您还应删除响应中的`ResponseMetadata`部分。这样可以避免有人看到`RequestId`并认为它是最新的，而实际上是几个小时前的风险。
+ **添加缓存元数据**：在响应中添加一个`CacheMetadata`部分会很有帮助。此部分可以报告存储该值的时间（用于衡量过时性）以及存储该值的客户端库和版本（在从一个版本无缝升级到另一个格式发生变化的版本时，这可能很有用）。
+ **确定表架构**：要通过写入操作确定缓存失效的主键，必须知道表的架构。您可以通过`describe_table`调用并在每个表首次使用时（仅一次）使用长期缓存来获取此信息。 ElastiCache 
+ **接受而不是构造客户端**：在构造函数中接受 DynamoDB 和 Redis 客户端实例（而不是根据传入的参数在 shim 中构建它们）的一个好处是，它允许构造函数的调用者确定细节，例如是否应该设置。`read_from_replicas=True`
+ **命名空间功能**：在构造函数中支持一个可选的命名空间可以很方便，该命名空间将所有缓存读取和写入该命名空间隔离开来。使用命名空间是测试的理想选择，因为每次使用不同命名空间的运行似乎都是从空缓存开始的，并且与之前的运行没有副作用。您还可以通过更改命名空间来模拟在生产环境中清空全部缓存。这可以通过为每个查找键自动添加前缀来实现。
+ **扫描缓存**：很难知道是否应该缓存`scan`呼叫。执行一次性全表扫描时，您不想在缓存中填充大量不会被第二次读取的扫描数据。另一方面，许多工作负载会重复扫描，尤其是针对较小的表，以便向多个下游使用者提供最新的完整表数据。一种折衷方案是实现一个系统，在该系统中，它需要两个调用，并且每个呼叫都具有相同的签名（在 TTL 时间段内），才能缓存生成的扫描响应。这样可以避免在一次性全表扫描期间填满缓存，同时启用紧密的扫描循环以获得缓存的好处。第一次扫描会在缓存中放置一个小占位符，以将请求标记为已发出一次。第二次扫描将令牌值替换为实际有效负载，后者可能高达 1 MB。