当前位置: 首页 > news >正文

PostgreSQL insert 偶发变慢的原因分析 —— 从缓存击穿到系统 I/O

一、背景与现象

1.1 问题场景

在一次生产环境性能监控中,我们发现数据库中部分 INSERT 操作持续变慢,延迟从毫秒级飙升到秒级,触发告警。

这些 SQL 操作并非批量导入(如 COPY),也不是长事务,而是普通的行级插入,主要涉及订单、账户、日志等高频表。

1.2 现象描述

通过监控采样与自研的 pga-snap 快照工具,可以看到:

  • 插入语句在活跃会话中停留较久;

  • 无明显锁等待事件;

  • 后端 wait_event_type 多为 IO;

  • 系统层磁盘 I/O 延迟升高。

初步判断是 磁盘 I/O 或缓存相关问题,但需要进一步验证。

1.3 已排除的非主因

排查中首先排除了以下可能:

  • 锁等待:无显著阻塞链;

  • 事务膨胀或 autovacuum 干扰

  • 大字段或 COPY 导入造成的写放大

  • ✅ 问题集中在 DML(尤其是 INSERT),具周期性。


二、排查过程

2.1 快照采集与工具

使用轻量级监控脚本 pga-snap 在触发慢 SQL 时自动抓取:

  • pg_stat_activity:当前活跃查询;

  • pg_buffercache:缓冲池驻留页;

  • pg_statio_user_tables:表块读取命中;

  • 系统层命令 iostat, vmstat:磁盘与 CPU 状况。

输出目录中主要分析文件包括:

  • 25_big_readers.txt —— 大查询与活跃会话;

  • 42_pg_buffercache_hot.txt —— 缓冲池中热点表命中率;

  • 90_sys_io_cpu.txt —— I/O 利用率。

2.2 系统层观察

在慢 SQL 发生时:

Device:   r/s   w/s   rkB/s   wkB/s  %util
nvme0n1   420   180   8,720   4,100   96.2

%util 接近 100%,说明磁盘 I/O 已饱和。

同时 vmstat 显示 b(阻塞进程)数量上升,表明数据库进程等待 I/O 返回。

2.3 数据库层观察

pg_stat_activity 显示 insert 查询运行时间较长,无锁等待。

pg_buffercache 抽样显示:

relname         rel_blocks  cached_blocks  pct_cached
order_main      120000      1800           1.5
order_index_1    80000      900            1.1

驻留率(cached ratio)低于 5%,即大多数页不在 shared_buffers 中。

这是明显的**缓存击穿(buffer cache miss)**现象。

2.4 分析路径

综合分析主要围绕五个方向展开:

  1. 缓存驻留与击穿;

  2. I/O 饱和;

  3. 插入页分配逻辑;

  4. 缓冲池竞争与淘汰策略;

  5. PostgreSQL 写入路径机制。


三、核心发现

3.1 INSERT 页访问机制

PostgreSQL 在插入数据时,需要:

  1. Free Space Map (FSM) 中查找可写页;

  2. 若页不在内存中,则从磁盘读入;

  3. 插入新元组并标记为 dirty;

  4. 写回由后台进程(bgwriter / checkpointer)异步完成。

若大量目标页在磁盘上(非缓冲池),每次插入都触发实际 I/O 读取。

3.2 直接原因:缓存击穿

通过驻留率分析(26_buffers_residency.txt),发现:

  • 插入表的 heap 与索引驻留率均 < 3%;

  • 相同快照周期内,系统层 r/s 明显升高;

  • 没有其他后台写入活动。

结论:INSERT 变慢的根本原因是 缓存击穿(cache miss)导致频繁磁盘读入目标页

3.3 关键证据

证据来源

观察结果

说明

pg_buffercache

heap 命中率低至 1.5%

热页被逐出

iostat

%util 约 95%

I/O 饱和

pg_stat_bgwriter

checkpointer 活动正常

无写入堆积

pg_statio_user_tables

heap_blks_hit << heap_blks_read

确认频繁读盘


四、深入机制解析

4.1 插入流程回顾

简化版流程如下:

Client → Executor → heap_insert()↓ 查找 Free Space Map↓ 目标页不在 shared_buffers → 读盘↓ 插入元组↓ 标记 buffer 为 dirty↓ 延迟写出

在高并发写入场景下,若 shared_buffers 太小或被大查询挤占,会导致:

  • 频繁淘汰热页;

  • 同一表页不断被加载、写出、再加载;

  • 实际形成 “写入读盘型 I/O 循环”。

4.2 为什么插入也会读盘?

许多开发者误以为 INSERT 只写不读,但 PostgreSQL 必须:

  • 读取页头和可用空间信息;

  • 维护可见性(MVCC);

  • 避免写入重叠元组。

因此,页不在缓冲池时,插入也必须先读盘。

4.3 冷页效应

当频繁插入的目标表分布在多个 segment 文件上时,页访问呈随机性;

随机 I/O 在 NVMe 下延迟虽低,但频繁 8KB 页读依然会显著影响 TPS。

4.4 Buffers 竞争与淘汰

PostgreSQL 使用 Clock-Sweep 算法维护 LRU 缓存:

  • usagecount 低的页容易被驱逐;

  • 大查询或全表扫描会快速消耗 buffer;

  • insert 页重新加载后 usagecount=1,若未命中即被替换。

这形成了典型的“写入冷启动”现象。


五、优化思路与对策

5.1 减少冷页命中

  • 使用 pg_prewarm 预加载热点表页;

  • 定期通过 pg_buffercache 采样分析驻留率;

  • 业务层控制批量 insert 分布,避免跨 segment 扩散。

5.2 优化缓存利用率

  • 提高 shared_buffers(一般可设为物理内存 25%~40%);

  • 设置 effective_cache_size 为系统缓存的合理估计;

  • 使用 pga-snap 动态热点追踪来识别真实热表。

5.3 I/O 层调优

  • 确认 effective_io_concurrency(SSD/NVMe 可设 32~64);

  • 使用异步 I/O 调度;

  • 监控 bgwriter 与 checkpointer 的写延迟。

5.4 表与索引策略

  • 合理分区:减少单表 segment 数量;

  • 瘦索引设计:降低插入附带写代价;

  • 更新统计信息,避免误选路径导致 heap miss。

5.5 持续监控

  • 动态热点集 (42_hotset_list.txt) 记录近期高频访问表;

  • 结合驻留率趋势(5% 以下视为风险区);

  • 定期快照、横向对比周期变化。


六、结论与经验总结

6.1 归因总结

层面

原因

对应证据

数据库内部

插入目标页未缓存

pg_buffercache

系统层

磁盘 I/O 饱和

iostat

参数层

shared_buffers 偏小

配置检查

机制层

缓冲页频繁替换

usagecount 分布低

6.2 通用防范思路

  • 提前识别并预热热点;

  • 定期监控驻留率与 delta;

  • 保持 WAL、checkpoint、cache 三者平衡;

  • 避免全表扫描扰动缓冲池。

6.3 后续计划

  • 将动态热点统计并入持续监控;

  • 建立驻留率基线模型;

  • 对低驻留、高 DML 表进行分区与 buffer pinning 实验。


总结一句话:

这次 insert 慢的根本原因不是锁,而是缓存击穿:
PostgreSQL 在写入冷页时仍需读盘,导致高频 DML 出现 I/O 延迟。
通过热页预热与动态热点监控,可以显著降低此类风险。

http://www.dtcms.com/a/597504.html

相关文章:

  • 简单的网站php开发教程高质量外链购买
  • MatplotlibDeprecationWarning
  • 织梦如何做网站地图西双版纳傣族自治州
  • 教程网站建设南宁制作企业网站
  • 刷题日常 5 二叉树最大深度
  • 信刻创新型近线+离线安全存储归档策略,保障电子档案全生命周期管理
  • Flutter for HarmonyOS开发指南(九):测试、调试与质量保障体系
  • 北京云主机网站源码做游戏网站要多少钱
  • 深圳自建站有哪些大公司邯郸企业网站建设价格
  • 项目分享| LocalAI-master:本地部署的OpenAI替代方案
  • 2.多线程进阶
  • 建湖网站定制重庆网站建设齐重庆零臻科技
  • 网站策划的内容wordpress3.8 中文标签
  • Rust评测案例:Rust、Java、Python、Go、C++ 实现五大排序算法的执行时间效率比较(基于 OnlineGDB 平台)
  • golang redis 管道
  • go-dongle v1.2.0 发布,新增 SM2 非对称椭圆曲线加密算法支持
  • ⚡️2025-11-11GitHub日榜Top5|Go AI代理开发框架
  • 网站建设g如何做设计网站页面
  • 智能推荐助力数据驱动决策模式提升效率
  • 博客系统 wordpressseo公司怎么样
  • 网站建设与管理 期末软件库资源共享
  • NetSonar网络诊断工具的安装与基本使用
  • 各国网站域名桂林市区有什么好玩的地方景点
  • 陕西省两学一做网站深圳今天新闻头条
  • Git Commend HandBook
  • MFC:微软基础类库的全面解析
  • 郑州网站建设技术托管营销推广方法有哪些
  • Python工具将本地Embedding转换成onnx格式
  • 手机类网站设计赣州新闻综合频道回放
  • 嘉兴网站免费制作判断网站开发语言