

# CPU
<a name="wait-event.cpu"></a>

当线程在 CPU 中处于活动状态或正在等待 CPU 时，会发生此事件。

**Topics**
+ [支持的引擎版本](#wait-event.cpu.context.supported)
+ [上下文](#wait-event.cpu.context)
+ [等待次数增加的可能原因](#wait-event.cpu.causes)
+ [操作](#wait-event.cpu.actions)

## 支持的引擎版本
<a name="wait-event.cpu.context.supported"></a>

此等待事件信息与所有的 RDS for PostgreSQL 版本相关。

## 上下文
<a name="wait-event.cpu.context"></a>

*中央处理单元 (CPU)* 是运行指令的计算机的组件。例如，CPU 指令执行算术运算并在内存中交换数据。如果查询增加了通过数据库引擎执行的指令的数量，则运行查询所花费的时间将增加。*CPU 调度*正在为进程提供 CPU 时间。调度由操作系统的内核编排。

**Topics**
+ [如何判断此等待何时发生](#wait-event.cpu.when-it-occurs)
+ [DBLoadCPU 指标](#wait-event.cpu.context.dbloadcpu)
+ [os.cpuUtilization 指标](#wait-event.cpu.context.osmetrics)
+ [CPU 调度的可能原因](#wait-event.cpu.context.scheduling)

### 如何判断此等待何时发生
<a name="wait-event.cpu.when-it-occurs"></a>

该 `CPU` 等待事件表示后端进程在 CPU 中处于活动状态或正在等待 CPU。您知道，当查询显示以下信息时会发生这种情况：
+ The `pg_stat_activity.state` column has the value `active`。
+ `pg_stat_activity` 中的 `wait_event_type` 和 `wait_event` 列都是 `null`。

要查看正在使用或等待 CPU 的后端进程，请运行以下查询。

```
SELECT * 
FROM   pg_stat_activity
WHERE  state = 'active'
AND    wait_event_type IS NULL
AND    wait_event IS NULL;
```

### DBLoadCPU 指标
<a name="wait-event.cpu.context.dbloadcpu"></a>

CPU 的性能详情指标为 `DBLoadCPU`。`DBLoadCPU` 的值可能与 Amazon CloudWatch 指标 `CPUUtilization` 的值不同。后一个指标是从 Hypervisor 中收集的，用于数据库实例。

### os.cpuUtilization 指标
<a name="wait-event.cpu.context.osmetrics"></a>

性能详情操作系统指标提供有关 CPU 利用率的详细信息。例如，您可以显示以下指标：
+ `os.cpuUtilization.nice.avg`
+ `os.cpuUtilization.total.avg`
+ `os.cpuUtilization.wait.avg`
+ `os.cpuUtilization.idle.avg`

性能详情将数据库引擎的 CPU 使用情况报告为 `os.cpuUtilization.nice.avg`。

### CPU 调度的可能原因
<a name="wait-event.cpu.context.scheduling"></a>

 操作系统（OS）内核处理 CPU 的调度。当 CPU 处于*活动状态*时，进程可能需要等待才能获得调度。CPU 在执行计算时处于活动状态。当它有一个未运行的空闲线程（也即，一个等待内存输入/输出的空闲线程）时也处于活动状态。这种类型的 I/O 主导着典型的数据库工作负载。

满足以下条件时，进程可能会等待获得 CPU 调度：
+ CloudWatch `CPUUtilization` 指标接近 100%。
+ 平均负载大于 vCPU 的数量，表示负载过重。您可以在性能详情中的操作系统指标部分找到 `loadAverageMinute` 指标。

## 等待次数增加的可能原因
<a name="wait-event.cpu.causes"></a>

当此事件的发生率超过正常（可能表示性能问题）时，典型的原因包括以下几点。

**Topics**
+ [突然猛增的可能原因](#wait-event.cpu.causes.spikes)
+ [长期高频的可能原因](#wait-event.cpu.causes.long-term)
+ [极端状况](#wait-event.cpu.causes.corner-cases)

### 突然猛增的可能原因
<a name="wait-event.cpu.causes.spikes"></a>

突然猛增的最可能原因如下：
+ 您的应用程序打开了太多与数据库同时连接。这种情况被称为“连接风暴”。
+ 您的应用程序工作负载在以下任一方面发生变化：
  + 新查询
  + 数据集的大小增加
  + 索引维护或创建
  + 新函数
  + 新的运营商
  + 并行查询执行增加
+ 您的查询执行计划已更改。在某些情况下，更改可能会导致缓冲区增加。例如，查询之前使用索引，而现在正在使用顺序扫描。在这种情况下，查询需要更多的 CPU 才能实现同样的目标。

### 长期高频的可能原因
<a name="wait-event.cpu.causes.long-term"></a>

长期反复出现的事件的最可能原因：
+ CPU 上同时运行的后端进程太多。这些进程可以是并行工件。
+ 查询执行不佳，因为它们需要大量缓冲区。

### 极端状况
<a name="wait-event.cpu.causes.corner-cases"></a>

如果所有可能的原因都不是实际原因，则可能会发生以下情况：
+ CPU 正在换入和换出进程。
+ 如果关闭了*大页*功能，CPU 可能正在管理页表条目。原定设置情况下，微型、小型和中型数据库实例类以外的所有数据库实例类都会开启内存管理功能。有关更多信息，请参阅 [适用于 RDS for PostgreSQL 的大页](PostgreSQL.Concepts.General.FeatureSupport.HugePages.md)。

## 操作
<a name="wait-event.cpu.actions"></a>

如果 `CPU` 等待事件主导着数据库活动，它不一定表示性能问题。只在性能下降时应对此事件。

**Topics**
+ [调查数据库是否导致 CPU 增加](#wait-event.cpu.actions.db-CPU)
+ [确定连接数量是否增加](#wait-event.cpu.actions.connections)
+ [响应工作负载变化](#wait-event.cpu.actions.workload)

### 调查数据库是否导致 CPU 增加
<a name="wait-event.cpu.actions.db-CPU"></a>

检查性能详情中的 `os.cpuUtilization.nice.avg` 指标。如果此值远低于 CPU 使用率，则非数据库进程是 CPU 的主要贡献者。

### 确定连接数量是否增加
<a name="wait-event.cpu.actions.connections"></a>

检查 Amazon CloudWatch 中的 `DatabaseConnections` 指标。您的操作取决于 CPU 等待事件增加期间该数量是增加还是减少。

#### 连接增加
<a name="wait-event.cpu.actions.connections.increased"></a>

如果连接数量增加，请将消耗 CPU 的后端进程数与 vCPU 的数量进行比较。以下是可能的情况：
+ 消耗 CPU 的后端进程数量少于 vCPU 的数量。

  在这种情况下，连接数量不是问题。但是，您仍然可以尝试降低 CPU 利用率。
+ 消耗 CPU 的后端进程数量大于 vCPU 的数量。

  在这种情况下，需考虑以下选项：
  + 减少连接到数据库的后端进程的数量。例如，实施连接池解决方案，例如 RDS 代理。要了解更多信息，请参阅[Amazon RDS 代理](rds-proxy.md)。
  + 升级实例大小以获得更多 vCPU 数量。
  + 如果适用，将一些只读工作负载重新导向到读取器节点。

#### 连接未增加
<a name="wait-event.cpu.actions.connections.decreased"></a>

检查性能详情中的 `blks_hit` 指标。寻找 `blks_hit` 增加与 CPU 使用率之间的相关性。以下是可能的情况：
+ CPU 使用率和 `blks_hit` 具有相关性。

  在这种情况下，找到与 CPU 使用率相关联的主要 SQL 语句，然后查找计划更改。您可以使用下面的方法之一：
  + 手动解释计划并将其与预期的执行计划进行比较。
  + 寻找每秒数据块命中量和每秒局部数据块命中量的增加。在性能详情控制面板的**主要 SQL** 部分中，选择 **Preferences**（首选项）。
+ CPU 使用率和 `blks_hit` 无关。

  在这种情况下，请确定是否出现以下任一情况：
  + 应用程序正在快速连接到数据库并断开与数据库的连接。

    通过打开 `log_connections` 和 `log_disconnections`，然后分析 PostgreSQL 日志来诊断此行为。考虑使用 `pgbadger` 日志分析器。有关更多信息，请参阅 [https://github.com/darold/pgbadger](https://github.com/darold/pgbadger)。
  + 操作系统已超载。

    在这种情况下，性能详情显示，后端进程使用 CPU 的时间比平时更长。在性能详情 `os.cpuUtilization` 指标或 CloudWatch `CPUUtilization` 指标中寻找证据。如果操作系统过载，请查看增强监控指标以进一步诊断。具体来说，请查看进程列表以及每个进程占用的 CPU 百分比。
  + 主要 SQL 语句消耗的 CPU 太多。

    检查与 CPU 使用率相关联的语句，看看它们是否可以使用更少的 CPU。运行 `EXPLAIN` 命令，并将重点放在影响最大的计划节点上。考虑使用 PostgreSQL 执行计划可视化工具。要试用此工具，请参阅 [http://explain.dalibo.com/](http://explain.dalibo.com/)。

### 响应工作负载变化
<a name="wait-event.cpu.actions.workload"></a>

如果您的工作负载发生了变化，请查找以下类型的更改：

新查询  
检查是否预计会出现新的查询。如果是，请确保他们的执行计划和每秒执行次数符合预期。

数据集的大小增加  
确定分区（如果尚未实施）是否有帮助。此策略可能会减少查询需要检索的页数。

索引维护或创建  
检查维护时间表是否符合预期。最佳实践是在高峰活动之外安排维护活动。

新函数  
检查这些功能在测试期间是否按预期运行。具体来说，检查每秒执行次数是否符合预期。

新的运营商  
检查它们在测试期间是否按预期运行。

运行并行查询的增加  
确定是否出现以下任一情况：  
+ 所涉及的关系或索引的规模突然增长，因此它们与 `min_parallel_table_scan_size` 或 `min_parallel_index_scan_size` 显著不同。
+ 最近对 `parallel_setup_cost` 或 `parallel_tuple_cost` 进行了更改。
+ 最近对 `max_parallel_workers` 或 `max_parallel_workers_per_gather` 进行了更改。