[译]PostgreSQL16-新特性-新增IO统计视图:pg_stat_io

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: [译]PostgreSQL16-新特性-新增IO统计视图:pg_stat_io

PostgreSQL16-新特性-新增IO统计视图:pg_stat_io我们DBA常遇到的问题是:如何优化数据库的IO操作获取PG服务产生的所有IO情况历来都是一个挑战。首先,PG将IO行为范围内为写WAL和读写数据目录(也就是数据文件)。真正的挑战是:理解围绕写入的二阶效应:通常数据的写入发生在事务提交后,即异步刷写,这就对理解哪个进程实际写入数据目录(以及何时)带来困难。当面临预分配的IOPS或者像Amazon Aurora付费单独的IO时,在云中这种情况更具挑战。通常情况下解决方案是查看系统中具有检测功能的部分(例如单个查询),从而至少了解活动发生的位置。上周末,由Andres Freund提交 Melanie Plageman的patch:IO活动可见性的重大改进Samay Sharma提供了文档。我的同事 Maciek Sakrejda 和我已经通过各种迭代审查了这个补丁,我们对它给 Postgres 可观察性带来的影响感到非常兴奋。下面是commit记录:感兴趣可查看:https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=a9c70b46dbe152e094f137f7e6ba9cd3a638ee25欢迎pg_stat_io,我们一起看下:


1、 Postgres 中查询系统范围的 I/O 统计信息


从开发分支编译个新的版本。PG16仍旧在开发中,甚至还没到beta阶段,绝对不应在生产环境中适应。可以从查询开始,看看pg_stat_io都跟踪了哪些信息:


SELECT * FROM pg_stat_io WHERE reads <> 0 OR writes <> 0 OR extends <> 0;

    | writes | extends | op_bytes | evictions |  reuses  | fsyncs |          stats_reset          
    ---------------------+-----------+------------+----------+---------+---------+----------+-----------+----------+--------+-------------------------------
    autovacuum launcher | relation  | normal     |       19 |       5 |         |     8192 |        13 |          |      0 | 2023-02-13 11:50:27.583875-08
    autovacuum worker   | relation  | normal     |    15972 |    2494 |    2894 |     8192 |     17430 |          |      0 | 2023-02-13 11:50:27.583875-08
    autovacuum worker   | relation  | vacuum     |  5754853 | 3006563 |       0 |     8192 |      2056 |  5752594 |        | 2023-02-13 11:50:27.583875-08
    client backend      | relation  | bulkread   | 25832582 |  626900 |         |     8192 |    753962 | 25074439 |        | 2023-02-13 11:50:27.583875-08
    client backend      | relation  | bulkwrite  |     4654 | 2858085 | 3259572 |     8192 |    998220 |  2209070 |        | 2023-02-13 11:50:27.583875-08
    client backend      | relation  | normal     |   960291 |  376524 |  159497 |     8192 |   1103707 |          |      0 | 2023-02-13 11:50:27.583875-08
    client backend      | relation  | vacuum     |   128710 |       0 |       0 |     8192 |      1221 |   127489 |        | 2023-02-13 11:50:27.583875-08
    background worker   | relation  | bulkread   | 39059938 |  590896 |         |     8192 |    802939 | 38253662 |        | 2023-02-13 11:50:27.583875-08
    background worker   | relation  | normal     |   257533 |  118972 |       0 |     8192 |    256437 |          |      0 | 2023-02-13 11:50:27.583875-08
    background writer   | relation  | normal     |          |  243142 |         |     8192 |           |          |      0 | 2023-02-13 11:50:27.583875-08
    checkpointer        | relation  | normal     |          |  390141 |         |     8192 |           |          |  18812 | 2023-02-13 11:50:27.583875-08
    standalone backend  | relation  | bulkwrite  |        0 |       0 |       8 |     8192 |         0 |        0 |        | 2023-02-13 11:50:27.583875-08
    standalone backend  | relation  | normal     |      689 |     983 |     470 |     8192 |         0 |          |      0 | 2023-02-13 11:50:27.583875-08
    standalone backend  | relation  | vacuum     |       10 |       0 |       0 |     8192 |         0 |        0 |        | 2023-02-13 11:50:27.583875-08
    (14 rows)

    大致上,此信息可以解释为:1)跟踪给定后台类型、IO对象类型(是否是临时表)和IO上下文2)主要统计数据是计数IO操作:读、写和extend(特殊类型的写,扩展数据文件)3)对于每个IO操作,以字节为单位解释统计信息(目前是块大小,默认8KB)4)shared buffer的驱逐次数、ring buffer重用次数和fsync调用次数进行了追踪PG16中系统范围的信息将始终可用。可以在PG手册中查看每个字段详细信息。注意,pg_stat_io显示了PG发起的逻辑IO操作。这通常会映射到真实的磁盘IO(尤其是写),操作系统由他自己的cache和batching机制,例如经常将8kb的写拆分为两个单独的4kb写入文件系统。通常我们假设这捕获了PG发起的所有IO,除了:1)WAL的IO2)特殊场景,比如表在表空间之间移动3)临时文件(比如排序中使用的,或者像pg_stat_statements扩展使用的)注意,追踪临时relations(和临时文件不一样):io_object = "temp relation"- 您可能熟悉它们在其他统计视图中被称为“本地缓冲区”有了这些基础知识,我们可以仔细研究一些用例来了解为什么这很重要。


    2、pg_stat_io用例

    2.1跟踪PG write IO活动


    PG中write的生命周期,以及目前在大多数统计中不可见的内容查看PG write时,需要了解查询运行时客户端看到的或者pg_stat_statement跟踪的东西。PG有一个复杂的机制确保write的持久性,允许客户端立即返回,相信服务已经以crash safe的方式持久化了数据。首先PG持久化数据左的第一件事是WAL日志。一旦日志写成功,客户端会接收到写成功的确认。但是之后发生的事情是额外的统计跟踪派上用场的地方。例如,如果您在pg_stat_statements中查看给定的 INSERT 语句,该shared_blks_written字段通常会告诉您几乎什么都没有,因为对数据目录的实际写入通常发生在稍后的时间,以便批量写入以提高效率并避免 I/O 峰值。除了写入 WAL 之外,Postgres 还将为写入更新共享(或本地)缓冲区。这样的更新会将有修改的缓冲区页面标记为“脏”。然后,在大多数情况下,另一个进程负责实际将脏页写入数据目录。需要考虑三种主要的流程类型:1)后台写进程:在后台持续运行,刷写脏页2)检查点进程:周期性执行checkpoint,或者WAL写到一定量时,将所有脏页全部刷写3)所有其他进程类型:包括常规客户端后端,如果他们需要驱逐脏页,则需要将脏页刷写。需要了解的主要事情是第三种情况的发生:因为他会大大拖慢查询速度。即使一个简单的SELECT也可能不得不突然刷写磁盘,然后才能在共享缓冲区中有足够的空间来读取数据。你可以从pg_stat_bgwriter视图中看到其中的一些活动,特别是名为buffers_字段。但这些信息不完整,没有明确考虑autovacuum活动,也没有让您了解刷写的根本原因(例如缓冲区驱逐)。可以观察pg_stat_io的writes字段,查看准确的汇总数据,以及PG中哪个进程实际最终将数据刷写磁盘


    2.2通过监控共享缓冲区逐出提高工作负载稳定性和调整 shared_buffers 大小


    pg_stat_io帮助澄清的一个重要的指标是:shared buffer(Shared buffer是固定大小,以页为单位)中一个缓冲页被驱逐的位置。什么内容缓冲在缓冲页中非常重要--尤其当工作集超过shared buffer大小时默认情况下shared_buffers为128MB(16000页)。想象下一个差劲的索引扫描耗光了128MB。当你突然读到完全不同的东西时会发生什么PG不得不从cache中驱逐一些老数据,也就是驱逐一个buffer page。驱逐带来两方面主要影响:1)以前在PG缓冲区中的数据,不在了。当然仍有可能在操作系统cache中。2)如果页驱逐时被标记为脏,进程驱逐时也会将老页写页磁盘。这两个方面对于调整共享缓冲区的大小都很重要pg_stat_io可以通过跟踪系统中每个后端类型evictions清楚的显示。如果您看到逐出突然激增,然后突然很多reads,它可以帮助您推断被逐出的缓存数据实际上在不久之后再次需要。如果有疑问,您可以使用pg_buffercache扩展来详细查看当前共享缓冲区的内容。


    2.3通过autovacuum和手动VACUUM跟踪累积的IO活动


    事实上,每个 Postgres 服务器偶尔都需要 VACUUM - 无论您是手动安排它,还是让 autovacuum 为您处理它。它有助于清理死行并使空间可重用,它冻结页面以防止事务 ID 回绕。但若没有正确调整,VACUUM和autovacuum会对IO产生巨大影响。最好的办法就是查看输出log_autovacuum_min_duration,会提供如下类似信息:


    LOG: automatic vacuum of table "mydb.pg_toast.pg_toast_42593": index scans: 0
    pages: 0 removed, 13594 remain, 13594 scanned (100.00% of total)
    tuples: 0 removed, 54515 remain, 0 are dead but not yet removable
    removable cutoff: 11915, which was 6 XIDs old when operation ended
    new relfrozenxid: 11915, which is 4139 XIDs ahead of previous value
    frozen: 13594 pages from table (100.00% of total) had 54515 tuples frozen
    index scan not needed: 0 pages from table (0.00% of total) had 0 dead item identifiers removed
    avg read rate: 0.113 MB/s, avg write rate: 0.113 MB/s
    buffer usage: 13614 hits, 13602 misses, 13600 dirtied
    WAL usage: 40786 records, 13600 full page images, 113072608 bytes
    system usage: CPU: user: 0.26 s, system: 0.52 s, elapsed: 939.84 s

    从中buffer usage您可以确定这个单个 VACUUM 必须读取 13602 页,并将 13600 页标记为脏。但是,如果我们想要获得更完整的画面,并且跨越我们所有的 VACUUM,该怎么办您现在可以通过查看标记为或与后端类型关联的pg_stat_io所有内容来查看系统范围内对 VACUUM 影响的测量:io_context = 'vacuum'autovacuum worker


    SELECT * FROM pg_stat_io WHERE backend_type = 'autovacuum worker' OR (io_context = 'vacuum' AND (reads <> 0 OR writes <> 0 OR extends <> 0));

      backend_type    | io_object | io_context |  reads  | writes  | extends | op_bytes | evictions | reuses  | fsyncs |          stats_reset          
      --------------------+-----------+------------+---------+---------+---------+----------+-----------+---------+--------+-------------------------------
      autovacuum worker  | relation  | bulkread   |       0 |       0 |         |     8192 |         0 |       0 |        | 2023-02-13 11:50:27.583875-08
      autovacuum worker  | relation  | normal     |   16306 |    2494 |    2915 |     8192 |     17785 |         |      0 | 2023-02-13 11:50:27.583875-08
      autovacuum worker  | relation  | vacuum     | 5824251 | 3028684 |       0 |     8192 |      2588 | 5821460 |        | 2023-02-13 11:50:27.583875-08
      client backend     | relation  | vacuum     |  128710 |       0 |       0 |     8192 |      1221 |  127489 |        | 2023-02-13 11:50:27.583875-08
      standalone backend | relation  | vacuum     |      10 |       0 |       0 |     8192 |         0 |       0 |        | 2023-02-13 11:50:27.583875-08
      (5 rows)

      在此特定示例中,autovacuum worker 总共读取了 44.4 GB 的数据(5,824,251 个缓冲页),并写入了 23.1GB(3,028,684 个缓冲页)。随着时间的推移跟踪这些统计数据,它将帮助您清楚地了解 autovacuum 是否是工作时间内 I/O 峰值的罪魁祸首。它还将帮助您更自信地进行更改以调整 autovacuum,例如,使 autovacuum 更具侵略性以防止膨胀。


      2.4批量读/写策略的可见性(顺序扫描和COPY)


      你在Postgres 中使用过 COPY 加载数据吗?或者使用顺序扫描从表中读取数据?您可能不知道,在大多数情况下,这些数据不会以常规方式通过共享缓冲区。相反,Postgres 使用一个特殊的专用环形缓冲区来确保大多数共享缓冲区不受此类大型活动的干扰。以前pg_stat_io,几乎不可能理解 Postgres 中的此活动,因为根本没有对其进行跟踪。现在,我们终于可以看到批量读取(通常是大型顺序扫描)和批量写入(通常是 COPY in),以及它们引起的 I/O 活动。您可以简单地过滤中的新值bulkwrite和值,并查看此活动:bulkreadio_context


      SELECT * FROM pg_stat_io WHERE io_context IN ('bulkread', 'bulkwrite') AND (reads <> 0 OR writes <> 0 OR extends <> 0);

        backend_type    | io_object | io_context |  reads   | writes  | extends | op_bytes | evictions |  reuses  | fsyncs |          stats_reset          
        --------------------+-----------+------------+----------+---------+---------+----------+-----------+----------+--------+-------------------------------
        client backend     | relation  | bulkread   | 25900458 |  627059 |         |     8192 |    754610 | 25141667 |        | 2023-02-13 11:50:27.583875-08
        client backend     | relation  | bulkwrite  |     4654 | 2858085 | 3259572 |     8192 |    998220 |  2209070 |        | 2023-02-13 11:50:27.583875-08
        background worker  | relation  | bulkread   | 39059938 |  590896 |         |     8192 |    802939 | 38253662 |        | 2023-02-13 11:50:27.583875-08
        standalone backend | relation  | bulkwrite  |        0 |       0 |       8 |     8192 |         0 |        0 |        | 2023-02-13 11:50:27.583875-08
        (4 rows)

        在此示例中,有495 GB 的批量读取活动和 21 GB 的批量写入活动,我们之前没有很好的识别方法。然而,最重要的是,我们不必担心evictions这里的计数——这些都是来自特殊批量读/批量写环形缓冲区的驱逐,而不是来自常规共享缓冲区的驱逐。


        3、Postgres 中 I/O 可观察性的未来


        pg_stat_io的基础工作在PG15之前就开始做了。PG15之前,统计信息跟踪必须通过统计信息收集器,速度慢且容易出错。这在历史上限制了轻松收集更高级统计数据的能力。随着增加pg_stat_io,现在更容易跟踪有关 Postgres 如何运行的附加信息。已经讨论的直接改进包括:1)跟踪系统范围的缓冲区缓存命中(以允许计算准确的缓冲区缓存命中率)2)累积的系统范围I/O 时间(不仅仅是当前存在的 I/O 计数pg_stat_io)3)更好的累积WAL 统计数据(即超越 pg_stat_wal 提供的)4)表和索引的附加I/O 跟踪


        4、原文


        https://pganalyze.com/blog/pg-stat-io

        相关实践学习
        使用PolarDB和ECS搭建门户网站
        本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
        阿里云数据库产品家族及特性
        阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
        目录
        相关文章
        |
        7月前
        |
        存储 传感器 数据可视化
        【软件设计师备考 专题 】IO接口的功能、类型和特性
        【软件设计师备考 专题 】IO接口的功能、类型和特性
        215 1
        |
        存储 关系型数据库 数据库
        深入了解 PostgreSQL:功能、特性和部署
        PostgreSQL,通常简称为Postgres,是一款强大且开源的关系型数据库管理系统(RDBMS),它在数据存储和处理方面提供了广泛的功能和灵活性。本文将详细介绍 PostgreSQL 的功能、特性以及如何部署和使用它。
        725 1
        深入了解 PostgreSQL:功能、特性和部署
        |
        4月前
        |
        SQL 关系型数据库 PostgreSQL
        PostgreSQL 如何通过身份证号码进行年龄段的统计?
        【8月更文挑战第20天】PostgreSQL 如何通过身份证号码进行年龄段的统计?
        538 2
        |
        7月前
        |
        设计模式 缓存 Java
        【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
        【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南( 实现可伸缩IO专题)— 上
        81 0
        |
        关系型数据库 大数据 PostgreSQL
        PostgreSQL16-新特性-并行聚合
        PostgreSQL16-新特性-并行聚合
        152 0
        |
        存储 关系型数据库 数据库
        探索PostgreSQL 14新特性--SEARCH和CYCLE
        探索PostgreSQL 14新特性--SEARCH和CYCLE
        93 0
        |
        7月前
        |
        SQL 关系型数据库 MySQL
        PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
        PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
        494 1
        |
        SQL 前端开发 API
        Flink教程(22)- Flink高级特性(异步IO)
        Flink教程(22)- Flink高级特性(异步IO)
        539 0
        |
        前端开发
        前端学习笔记202305学习笔记第二十九天-Socket.io文本编辑实时共享之响应式和视图数据渲染1
        前端学习笔记202305学习笔记第二十九天-Socket.io文本编辑实时共享之响应式和视图数据渲染1
        65 1
        |
        SQL 关系型数据库 Java
        PostgreSQL统计信息的几个重要视图
        PostgreSQL统计信息的几个重要视图
        299 1