

# 解决 Amazon DynamoDB 中的延迟问题
<a name="TroubleshootingLatency"></a>

如果您的工作负载出现高延迟，您可以分析 CloudWatch `SuccessfulRequestLatency` 指标，并检查平均延迟和以百分位数指标表示的中位数延迟（p50），看看它是否与 DynamoDB 有关。报告的 `SuccessfulRequestLatency` 有一些变化是正常的，偶尔的峰值（尤其是在 `Maximum` 统计数据中和较高的中位数）不用担心。但是，如果 `Average` 统计数据或 p50（中位数）显示急剧增加并且持续存在，则应检查 Amazon Service Health Dashboard 和 Personal Health Dashboard 来了解更多信息。一些可能的原因包括表中项目的大小（1 KB 的项目和 400 KB 的项目延迟会有所不同）或查询的大小（10 个项目与 100 个项目会有不同）。

百分位数指标（p99、p90 等）有助于您更好地了解延迟分布情况。例如：
+ p50（中位数）显示工作负载的典型延迟。
+ p90 显示 90% 的请求比该值更快。
+ p99 有助于确定影响 1% 请求的最坏情况延迟。

p99 值高而 p50 值正常，可能表示影响一小部分请求的零星问题，而 p50 值持续升高可能表明性能有所下降。

**注意**  
要分析自定义百分位数值（例如 p99.9），可以在 CloudWatch 指标统计数据字段中手动输入所需的百分位数（例如 p99.9）。这样，您就可以评估超出下拉列表中所列默认百分位数的延迟分布。

延迟指标会有一些变化，尤其是百分位数较高，这是意料之中的，可以看作是 DynamoDB 驱动的后台操作的结果，这些操作有助于为存储在 DynamoDB 表中的数据或针对临时基础设施问题保持高可用性和持久性。

如有必要，可以考虑向 Amazon Web Services 支持 提交支持案例，并根据您的运行手册继续评估应用程序的任何可用回退选项（例如，如果您使用多区域架构，则撤出区域）。您应该记录缓慢请求的请求 ID，以便在提交支持案例时，向 Amazon Web Services 支持 提供这些 ID。

该 `SuccessfulRequestLatency` 指标仅衡量 DynamoDB 服务内部的延迟，而不包括客户端活动和网络往返时间。要详细了解从您的客户端调用 DynamoDB 服务的总体延迟，您可以在 Amazon SDK 中启用延迟指标日志记录。

**注意**  
对于大多数单例操作（通过完全指定主键值来应用于单个项目的操作），DynamoDB 提供个位数毫秒级 `Average SuccessfulRequestLatency`。此值不包括访问 DynamoDB 端点的调用方代码的传输开销。对于多项目数据操作，根据结果集的大小、返回的数据结构的复杂性以及应用的任何条件表达式和筛选条件表达式等因素，延迟将会有所差异。对于使用相同参数对同一数据集重复执行的多项目操作，DynamoDB 将提供高度一致的 `Average SuccessfulRequestLatency`。

考虑以下一种或多种策略来减少延迟：
+ **重用连接：**默认情况下，DynamoDB 请求通过经过身份验证的会话经由 HTTPS 发出。启动连接需要多次往返并需要时间，因此第一个请求的延迟高于后续旨在重用连接的请求。通过已初始化的连接发出的请求可提供 DynamoDB 的一致低延迟。为了避免建立新连接的延迟开销，如果没有发出其它请求，您可能希望通过每 30 秒发送一个 `GetItem` 请求来实现“保持连接”机制。
+ **使用最终一致性读取：**如果您的应用程序不需要强一致性读取，请考虑使用默认的最终一致性读取。最终一致性读取的成本更低，并且可以来自多个可用区，这样就可以选择与请求者位于同一位置的可用区，从而减少延迟。有关更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。
+ **实现请求对冲：**对于非常低的 p99 延迟要求，可以考虑实施请求对冲。借助请求对冲，如果初始请求没有足够快地收到响应，则发送第二个等效请求并让它们竞争，第一个响应获胜。这样可以缩短尾部延迟，但代价是需要一些额外的请求。您可以决定在发送第二个请求之前等待多长时间。对冲更便于读取。对于写入，请使用基于时间戳的排序来确保对冲请求被视为在第一次尝试时发生，从而防止乱序更新。[Timestamp writes for write hedging in Amazon DynamoDB](https://www.amazonaws.cn/blogs/database/timestamp-writes-for-write-hedging-in-amazon-dynamodb) 中讨论了这种方法。
+ **调整请求超时和重试行为：**从客户端到 DynamoDB 的路径遍历许多组件，每个组件的设计均考虑了冗余。请考虑以下方面：
  + 网络韧性
  + TCP 数据包超时
  + DynamoDB 的分布式架构

  默认的 SDK 行为已针对大多数应用程序进行了优化。但是，您可以实施快速失效机制策略并调整超时设置。如果请求花费的时间比正常情况长得多，则最终获得成功的可能性较小。通过快速失效机制和重试，您可能会很快通过不同的途径取得成功。这与请求对冲类似，但会结束第一个请求，而不是让此请求继续。

  避免将超时值设置得过低。超时过低可能导致由客户端引起的可用性问题。例如，50 毫秒的套接字超时可能会在网络延迟高峰期间导致连接错误，例如在接近 Amazon EC2 实例的单流流量带宽限制时。仔细权衡较低超时的好处与应用程序可用性面临的潜在风险，并首选对冲而非较短的超时。

   有关此主题的实用讨论，请参阅 [Tuning Amazon Java SDK HTTP request settings for latency-aware Amazon DynamoDB applications](https://www.amazonaws.cn/blogs/database/tuning-aws-java-sdk-http-request-settings-for-latency-aware-amazon-dynamodb-applications/)。
+ **缩短客户端与 DynamoDB 端点之间的距离：**如果您的用户分布在全球，请考虑使用[全局表 - 多活、多区域复制](GlobalTables.md)。使用全局表，您可以将表复制到您希望表在其中可用的指定 Amazon 区域。您可以将数据的副本放在离终端用户更近的位置，以减少读写操作期间的网络延迟。有关有效使用 DynamoDB 全局表的更多信息，请参阅《Amazon Prescriptive Guidance》中的 [Using Amazon DynamoDB global tables](https://docs.amazonaws.cn/prescriptive-guidance/latest/dynamodb-global-tables/introduction.html)。
+ **使用缓存：**如果流量的读取量很大，请考虑使用以下缓存服务之一：
  + DynamoDB Accelerator（DAX）：适用于 DynamoDB 的完全托管式高可用性内存缓存，可提供高达 10 倍的性能改进（从毫秒到微秒），即使每秒数百万个请求也是如此。有关 DAX 的更多信息，请参阅[利用 DynamoDB Accelerator（DAX）实现内存中加速](DAX.md)：
  + Amazon ElastiCache：一种完全托管式内存缓存服务，可以与 DynamoDB 集成，以使用旁路缓存模式来提高读取性能。有关更多信息，请参阅《Amazon Prescriptive Guidance》中的 [Integrating Amazon DynamoDB and Amazon ElastiCache by using read-through caching](https://docs.amazonaws.cn/prescriptive-guidance/latest/dynamodb-elasticache-integration/introduction.html)。