

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

# 缓存读取行为
<a name="cache-read"></a>

shim 应仅缓存对 DynamoDB 进行的最终一致性读取调用。这包括 `get_item`、`batch_get_item`、`query` 和 `scan`。它不应缓存强一致性读取调用或事务性读取调用，因为这些调用本质上不希望看到数据的缓存版本。

缓存条目必须了解请求的签名，才能识别后续的等效请求。每个调用的签名由影响结果的请求的所有参数组成。对于`get_item`呼叫，签名包括`TableName`、`Key``ProjectionExpression`、和`ExpressionAttributeNames`参数。对于查询调用，它包括`TableName`、`IndexName`、`KeyConditions``FilterExpression`、`ScanIndexForward`、和`Limit`参数。如果对同一函数的两个调用具有相同的签名，则可能是缓存命中。

以下是`get_item`呼叫的逻辑流程示例：
+ 检查是否`ConsistentRead=true`。如果是，请直接调用数据库并返回结果。强一致性调用不应使用缓存。
+ 计算通话的签名。将`TableName`、`Key``ProjectionExpression`、和`ExpressionAttributeNames`参数进行哈希处理以获得单个字符串签名值。
+ 查看是否存在使用此签名密钥的缓存条目。如果是，则是缓存命中，因此将其返回。
+ 如果不是，则将调用传递到数据库，检索结果，填充此签名的缓存条目，然后返回结果。存储物品时，请指定存活时间 (TTL) 到期时间。

例如，假设你有这样的代码：

```
cache_client.get_item(
  TableName='test',
  Key={ 'PK': { 'S': '123' } },
  ProjectionExpression='#attr1, #attr2',
  ExpressionAttributeNames={
    '#attr1': 'agent',
    '#attr2': 'count'
  },
  ConsistentRead=False
)
```

在内部`cache_client`，代码计算呼叫的哈希签名。签名源于对`TableName`、`Key`、和参数的串联进行哈希处理。`ProjectionExpression` `ExpressionAttributeNames`任何哈希系统都可以使用，只要它是确定性的，并且生成单个字符串值。在本例中，我们假设它哈希值为。`0xad4c812a`此哈希值标识了这组参数。

如果再打一个相同的电话怎么办，只是`#attr1`它被重命名了`#attribute1`？ 该通话是否应该被视为具有相同的签名？ 理想情况下，是的，因为它在语义上是相同的，但是弄清楚每个呼叫的语义等同性的开销是不切实际的。盲目地对参数值进行哈希处理并要求精确匹配要快得多。规则是：如果呼叫*实际上*是同一个呼叫，则有资格获得缓存命中，但如果它们*基本上*是相同的呼叫，则不符合缓存命中资格。

然后`cache_client`，代码在里面 ElastiCache 查找存储在下的项目缓存中的条目`0xad4c812a`。如果该条目存在，那就是缓存命中。如果不是，则从数据库中获取该值并存储在中 ElastiCache 供以后缓存中使用。

以下是具有三组不同表、键和投影参数的三个`get_item`调用的缓存样子。


| 伪码 | ElastiCache 密钥计算 | ElastiCache 价值 | 
| --- | --- | --- | 
| `get_item(t1, k1, p1)` | `hash('get', t1, k1, p1) = 0xad4c812a` | `{ 'Item': … }` | 
| `get_item(t1, k1, p2)` | `hash('get', t1, k2, p2) = 0x045deaab` | `{ 'Item': … }` | 
| `get_item(t1, k2, p1)` | `hash('get', t1, k2, p1) = 0x9cda78af` | `{ 'Item': … }` | 

其他调用（例如`query`和`scan`）的工作方式相同，但它们的签名由不同的参数组成。

这种设计可能会让你想起 HTTP 缓存代理的工作原理。如果它再次看到相同的请求，它可以返回先前请求的响应。HTTP 中*相同请求*的定义主要基于查询字符串。在 DynamoDB 中，传递给函数的调用类型和参数集会影响其结果。

还有一个步骤。对于项目缓存来说，重要的是要在每个项目的主键和主动用于缓存该项目的哈希列表之间保持映射。这将在写入操作期间发挥作用，如下一节所述。因此，除了之前的键和值之外，还会有额外的缓存条目，例如：


| 操作 | ElastiCache 密钥计算  | ElastiCache 价值 | 
| --- | --- | --- | 
| 跟踪表`t1`、键的条目列表 `k1` | `hash('list', t1, k1)` | ( `0xad4c812a, 0x045deaab` ) | 
| 跟踪表`t1`、键的条目列表 `k2` | `hash('list', t1, k2) ` | ( `0x9cda78af` ) | 