用等待事件,观测网络对 PostgreSQL 性能的影响

数据库 PostgreSQL
pg_stat_activity 中的 “等待事件” 信息可以告诉我们,有关性能和网络拥塞的许多详细信息。不仅仅是事件的汇总,在两个等待事件和模式之间的间隙,也有很多信息需要深入研究。正确地收集和分析数据,可以从 PostgreSQL 的角度检测发生的事情,以及它受到网络的影响程度。

介绍

在 PostgreSQL 数据库和应用服务器之间会看到许多的基础设施层,这是很常见的。最常见的有连接池、负载均衡器、路由器、防火墙等。对于这些组件所涉及的网络跳点及其对整体性能产生的额外开销,我们经常会忽视它们的影响,或认为这些开销是理所当然的。但在许多情况下,它可能会导致严重的性能损失和整体吞吐量的下降。

如何检测和衡量影响

没有简单的机制来衡量网络开销的影响。但是,对 pg_stat_activity 中的 wait_events 进行非常仔细的分析,可以尽可能地让我们清楚其影响。因此,我们应该对等待事件进行采样。有许多方法可用于等待事件采样,包括扩展。但是在用户环境中安装用于等待事件采样的特殊工具或扩展,不是很方便。不过,我们可以使用 pg_gather 作为收集和研究等待事件的方法,因为它是一个独立的 SQL 脚本,不需要在数据库系统上安装任何东西。它的设计也非常轻巧。每次会话将收集 2,000 个样本。

pg_gather 分析报告可以显示与每个会话关联的等待事件和其他信息。

pid

state

User

client

Last statement

Connection Since

Transaction Since

xmin age

Statement since

State since

waits

6594

active

postgres

10.197.42.240

COPY pgbench_accounts (aid, bid, abalance, filler) TO stdout;

00:00:08.650416

00:00:08.644447

0

00:00:00

00:00:00

ClientWrite:14, DataFileRead:278, CPU:1708

但是,本教程将仅讨论和重点介绍其中的等待事件部分,同时介绍不同类型的业务负载,以及如何在等待事件中查看网络性能。

案例 1: 查询检索大量行

让我们考虑一下在另一台机器上用 pg_dump 进行逻辑备份的情况。如果网络速度很快,我们可能会看到大量的 CPU 使用率和 “DataFileRead” 一类的等待事件。

waits

ClientWrite:14,DataFileRead:278,CPU:1708

当然,还有 “ClientWrite” 事件,在本例中,这是与将数据发送到客户端(pg_dump)相关的等待事件。如果客户端是像 psql 这样的轻量级工具,并且网络速度非常快,则 “ClientWrite” 可能会变得几乎不可见。

但是,让我们来看看如果网络变慢,等待事件会是什么样子。

waits

CPU:19,ClientWrite:1821,ClientRead:158,DataFileRead:2

我们可以看到 CPU 使用率和 “DataFileRead” 等待事件下降了,这表明服务端整体的会话活动速度变慢了。同时,“ClientWrite” 上升到了 1821,这表明会话花费了大量时间将数据发送到其客户端(pg_dump)。还有 “ClientRead”,表明 pg_dump 的确认需要时间。

“ClientWrite” 中的飙升与客户端工具无关。以下是一个常规的 psql 会话,在查询检索大量记录时的屏幕截图。

waits

CPU:129,ClientWrite:1869,DataFileRead:2

在这些情况下,这种过多的 “ClientWrite” 足以暴露出问题。

案例 2: 批量数据加载

这与前一个案例相反。但是 PostgreSQL 对于批量数据的写入操作,需要做更多的工作。以下等待事件是在非常快速/低延迟的网络环境中捕获到的。

waits

CPU:1725,DataFileExtend:94,WALWrite:75,WALSync:63,DataFileWrite:41,WALBufMapping:2

显然,PostgreSQL 进程必须在 “DataFileExtend”、“WALWrite” 和 “WALSync” 这些事件上花费时间。现在,如果网络速度变慢,随着性能瓶颈的出现,我们看到的许多等待事件可能会变得不可见。

以下是通过较慢的网络加载相同批量数据的等待事件。

waits

CPU:3,ClientRead:1997

正如我们所看到的,“ClientRead” 已成为主要的等待事件。这意味着服务器会话花费了更多时间从其客户端读取数据。

在许多系统中,这种变化可能并不明显,但总体上 “ClientRead” 会变得更加突出。

案例 3: 对事务的影响

有人可能会问,事务有什么特别之处。在 OLTP 业务负载下,语句可能简单而短小,这会导致任何可观察到的网络影响。但是服务器和客户端之间的来回通信,可能会导致语句与最终的提交或回滚之间出现不必要的延迟。也就是说,在每个语句之间会有延迟/间隙。

以下是使用 pgbench 在快速网络环境处理小事务发生的等待事件。

waits

WALWrite:714,CPU:573,WALSync:442,ClientRead:139,DataFileRead:35,DataFileWrite:18,transactionid:17,BufferContent:2, Net/Delay*:59

显然,存在大量 WAL 相关的等待事件和 CPU 使用率。但是我们可以看到,也有相当多的 “ClientRead”。发生这种情况是因为小事务会有很多网络交互。ClientRead 对于事务来说是不可避免的,预计在其中出现 5-10% 是可以的。

但随着网络速度变慢,“ClientRead” 变得越来越突出。以下是在较慢的网络环境上,相同的 pgbench 事务工作负载的信息。

waits

DataFileRead:1,WALSync:20,CPU:23,ClientRead:1700,transactionid:2, Net/Delay*:252

在这种情况下,ClientRead 成为了最突出的等待事件。

您可能想知道,显示的 “Net/Delay*” 是什么?新版本的 pg_gather(版本 21)中提供了这种额外的分析,用以评估事务块之外的延迟。有关详细信息,请参阅下一节。

案例 4: 连接利用率

随着网络延迟的增加,客户端连接将无法尽可能地使用服务器会话。服务器会话必须在 “ClientRead”/“ClientWrite” 事件上等待或处于空闲状态。无论哪种方式,它都会极大地影响系统的吞吐量。

在事务中,延迟被捕获为 “ClientRead”,但不会捕获到两个事务之间的延迟,因为会话暂时会变为 “空闲”。pg_gather 新版本会对这种瞬时切换到空闲状态的过程进行估计,作为服务器浪费时间或 “Net/Delay*”。这可能是由于网络延迟或应用程序响应不佳引起。从数据库方面来看,很难区分它们。但是 “Net/Delay*” 可以很好地说明浪费了多少服务器时间。

如果可以在应用程序服务器上安装 PostgreSQL 客户端工具,则很容易模拟负载,来研究网络延迟和应用程序端响应延迟,并将其与实际数据进行比较。

当客户端和服务器之间有大量的来回通信时,延迟会变得更加明显。这可以通过创建单个语句文件轻松测试出来。

echo "SELECT 1" > query.sql

这可以通过 TCP 连接对远程数据库执行指定秒数。

pgbench -h 10.197.42.1 -T 20 -f query.sql

在服务器之间采用快速网络连接的情况下,可以获得以下结果,以作为单个会话的 TPS。

...
latency average = 0.030 ms
initial connection time = 5.882 ms
tps = 32882.734311 (without initial connection time)

但 pg_gather 的等待事件分析表明,在 Net/Delay* 上花费了更多的时间。

waits

ClientRead:38,CPU:566, Net/Delay*:1392

这是有道理的,因为 “SELECT 1” 在服务器上没有太多事情要做,而且这种业务负载都是关于发送来回通信的。

使用本地 Unix 套接字连接时,单个会话吞吐量增加了一倍多!

latency average = 0.013 ms
initial connection time = 1.498 ms
tps = 75972.733205 (without initial connection time)

但等待事件分析告诉我们,客户端-服务器通信仍然是一个主要的时间消耗点。

waits

ClientRead:271,CPU:575, Net/Delay*:1148

这种高度交互的业务负载,可以采用服务端编程(存储过程/函数)甚至扩展来优化。有趣的是,当使用 Unix 套接字连接时,与 TPS 相比,CPU 使用率的比例较小;这是需要重点注意的一个地方。“ClientRead” 增加是因为从客户端传输了更多数据。

如果在这种情况下网络速度变慢,则 “Net/Delay*” 也会增加,并且 CPU 使用率和 TPS 会下降,因为会话在处理两个语句之间要花费更多时间。

waits

CPU:51, Net/Delay*:1882

由于这种特定的业务负载没有事务,并且要发送到服务器的数据较少,因此正如我们所看到的,“ClientRead” 可能会下降到一个不明显的水平。

总结

pg_stat_activity 中的 “等待事件” 信息可以告诉我们,有关性能和网络拥塞的许多详细信息。不仅仅是事件的汇总,在两个等待事件和模式之间的间隙,也有很多信息需要深入研究。正确地收集和分析数据,可以从 PostgreSQL 的角度检测发生的事情,以及它受到网络的影响程度。更重要的是,分析过程可以不依赖数据库托管机器和操作系统级工具。无需任何复杂的工具或框架即可实现此目的。像这样独立的 SQL 脚本可以方便地发现问题和瓶颈。尽管这篇教程专门介绍了网络,但对于等待事件的分析,在许多情况下可能是通用的。

责任编辑:武晓燕 来源: 红石PG
相关推荐

2022-11-17 08:00:18

JavaScript错误性能

2022-12-15 08:00:38

JavaScript错误性能

2012-05-07 08:18:42

程序日志性能

2011-05-24 16:01:51

OpenFlow影响

2012-08-28 11:14:18

IBMdw

2024-07-05 15:52:34

2023-08-11 09:54:18

2015-02-12 09:14:41

2010-05-24 13:22:37

Swap空间

2010-12-27 14:16:42

2013-12-10 10:25:31

云计算趋势网络构架

2011-08-23 12:20:47

笔记本评测

2014-03-06 14:21:28

2022-06-07 08:18:49

懒加载Web前端

2022-06-21 17:41:57

工业4.0网络架构

2012-02-08 09:27:18

云计算企业网络

2012-02-08 13:52:35

云计算

2013-12-02 09:09:12

网络性能管理员网管

2011-05-25 14:42:37

Oracle空间管理系统性能

2009-06-30 15:02:41

磁盘排序Oracle数据库性能
点赞
收藏

51CTO技术栈公众号