DeepSeek总结的Postgres 性能衰退

news2026/4/30 0:24:04
来源https://mydbanotebook.org/posts/postgres-performance-regression-are-we-there-yet/Postgres 性能衰退我们到了吗2026年4月15日 · 2402 词 · 预计阅读 12 分钟每年PostgreSQL 都在变得更快。研究人员对从 8 版到 16 版的优化器进行基准测试发现每个主要版本平均有 15% 的性能提升。这是十年来持续、可衡量的进步。该项目自 1996 年以来一直在这样做。因此当有头条新闻声称 Linux 7.0 刚刚将 PostgreSQL 的吞吐量减半时DBA、系统管理员和 DevOps 开始恐慌尤其是那些使用计划尽快搭载 Linux 7.0 内核的 Ubuntu 26.04 LTS 的人。在按下恐慌按钮之前值得先深吸一口气。实际情况更加微妙。让我带你了解一下实际发生了什么这对你的部署意味着什么以及你应该真正担心什么。首先一点内核理论请耐心听我说。我保证这是必要的。你的操作系统内核负责决定哪个程序在何时运行在 CPU 上。这被称为调度。当一个程序在执行过程中被中断以让另一个程序运行时这被称为抢占。如果你在服务器上运行 PostgreSQL 已有一段时间你会知道标准的建议PostgreSQL 应该拥有这台机器。它应该是这台主机上唯一重要的东西。我们通常会禁用 OOM killer这样内核就不会在内存压力下决定牺牲 PostgreSQL 的后台进程。我们调整vm.swappiness以将 PostgreSQL 的数据保留在内存中。整个理念是阻止操作系统对数据库进行“二次猜测”。抢占模式符合相同的理念。把它想象成一位正在进行精细手术的外科医生。你不希望有人在手术中途拍拍他们的肩膀说“你能快点看看别的东西吗”当 PostgreSQL 深入到一个关键部分时我们同样不希望内核打断它。不同的抢占模式代表了不同的权衡。PREEMPT_NONE(旧的服务器默认值): 内核几乎从不中断正在运行的程序。程序一直运行直到它自愿放弃 CPU或者直到它进行系统调用。更少的上下文切换更多的时间做实际工作。PREEMPT_NONE无中断线程运行直到自愿让出PREEMPT_FULL: 内核几乎可以在任何点中断任何正在运行的程序。这对响应能力和实时应用程序很有好处。但对服务器工作负载的吞吐量不利。PREEMPT_FULL中断可能发生在任何地方、任何时间点PREEMPT_LAZY(Linux 7.0 新增): 一个折衷方案。内核会抢占线程但是是“懒惰”地等待一个自然的机会而不是立即强制中断。旨在降低PREEMPT_FULL的开销同时保持内核调度模型的简洁。PREEMPT_LAZY仅在自然调度边界中断在过去的 20 多年里服务器内核都搭载了PREEMPT_NONE。PostgreSQL 就是考虑到这个现实而构建的。Linux 7.0 改变了这一点。Peter Zijlstra 的提交7dadeaa6e851在现代架构上移除了PREEMPT_NONEarm64、x86、powerpc、riscv、s390、loongarch。所有架构都是。内核现在只提供PREEMPT_FULL和PREEMPT_LAZY。为什么这会影响 PostgreSQL 的性能PostgreSQL 在多个地方使用自旋锁尤其是在其缓冲区管理器中。自旋锁是一种锁机制线程在等待锁可用时不会进入睡眠状态而是会在一个紧密循环中不断检查。想想《怪物史莱克》中坐在后座被绑住的驴子“我们到了吗我们到了吗我们到了吗”这听起来很浪费但对于非常短期的锁PostgreSQL 的缓冲区管理器使用的那种这实际上比让线程休眠再唤醒的开销要快。自旋锁背后的关键假设是持有锁的线程将很快释放它。没有人会在一个 20 纳秒的关键部分中间抢占该线程。在PREEMPT_NONE下这个假设成立。锁持有者一直运行直到完成。其他自旋等待的线程不会等太久。在PREEMPT_LAZY下内核可以决定抢占一个持有自旋锁的线程。该线程被暂停。等待该锁的所有其他线程继续自旋燃烧 CPU 周期直到调度器决定恢复原始线程。下面是几个线程下的情况PREEMPT_LAZY下的自旋锁竞争线程 1 在持有锁时被抢占所有其他线程无用地自旋直到它被恢复理论上这是一个真正的问题。在实践中实际发生的事情更有趣。基准测试实际显示了什么AWS 的 Salvatore Dipietro 在一个 96 个 vCPU 的 Graviton4 实例上运行了pgbench1024 个客户端96 个线程使用超过 100GB 的共享缓冲区池。与 Linux 6.x 相比他得到了 0.51 倍的吞吐量并向内核邮件列表报告了这一点。基准测试脚本明确设置了huge_pagesoff。这一个细节关系重大。Andres Freund 深入研究了邮件列表线程发现了真正的罪魁祸首不是自旋锁机制本身而是在持有自旋锁时发生的TLB 未命中和轻微缺页错误。以下是实际发生的情况。没有大页PostgreSQL 的共享内存使用标准的 4KB 页面映射。在超过 100GB 的缓冲区池上对每个页面的第一次访问都会导致一次轻微缺页错误。当这个轻微缺页错误发生在持有自旋锁时该线程会停滞。等待该锁的所有其他线程继续自旋。PREEMPT_LAZY然后偶尔会调度出停滞的锁持有者使情况变得更糟但根本问题已经是缺页错误而不是抢占模式。Andres 证实了这一点当他启用大页时他无法重现性能衰退。当他禁用大页时竞争出现了。Salvatore 也证实了这一点。他重新运行了基准测试这次在系统上启用了透明大页 (THP)他发现 THP 修复了之前的行为在 Linux 6.x 和 Linux 7.0 上吞吐量都恢复到了大约 185k tps。大页和 THP 通过不同的机制工作但都消除了导致竞争的 4KB 缺页错误问题。还有第二个值得注意的细节。基准测试中处于竞争状态的自旋锁是StrategyGetBuffer()它仅在缓冲区池预热期间触发即 PostgreSQL 首次将页面加载到共享内存时。一旦缓冲区池达到稳定状态并且空闲列表清空该路径就不会再被命中。该基准测试测量的是一个瞬态的预热阶段并将其呈现为稳态性能。PostgreSQL 中至少还有一个自旋锁可能在新抢占模型下发生竞争但其并发获取的上限要低得多。Andres 直言不讳地说一个 100GB 的冷缓冲区池没有大页运行着比 CPU 核心数多 10 倍的活动连接并且仅在预热期间这不是一个现实的生产场景。那么你应该害怕吗对于在裸机或专用虚拟机上配置良好的部署可能不会。如果你已经在主机上启用了大页或 THP并且你的工作负载不是一个具有巨大缓冲区池的极端冷启动场景那么 Linux 7.0 的更改不太可能在稳态下影响你。在做出任何决定之前请使用你实际的工作负载和实际配置进行基准测试。在两种情况下情况更加微妙。第一如果你在没有大页或 THP 的情况下在高度并行的机器上运行大型共享缓冲区。在这种情况下PREEMPT_LAZY确实会加剧预热期间的自旋锁竞争。在这种配置下PREEMPT_NONE下也存在竞争PREEMPT_LAZY只是让它变得更糟。解决方法是启用大页或 THP而不是固定你的内核版本。第二如果你在容器中运行 PostgreSQL。这是值得花时间关注的担忧因为它没有得到足够的重视。真正的问题大页、THP 和容器大页和 THP 都能缓解性能衰退。在裸机上启用其中任何一种都很简单。在容器化环境中这从困难到不可能这是一个早在 Linux 7.0 之前就存在的普遍 PostgreSQL 性能问题。THP 由/sys/kernel/mm/transparent_hugepage/enabled控制这是一个主机级别的 sysfs 路径。Sysfs 在 Linux 中没有命名空间隔离这意味着容器无法修改它。主机配置了什么该主机上的每个容器就继承什么无法从内部覆盖。显式大页也有同样的限制。主机内核在容器启动前通过vm.nr_hugepages预留一个池。如果主机配置了容器可以从该池中消费但它不能创建或调整池的大小。Incus一个完全开源的系统容器管理器确实允许limits.hugepages通过 hugetlb cgroup 限制给定容器可以消费多少个大页但主机池必须首先存在。在 Incus 中运行 PostgreSQL 的一位读者正好报告了这个问题你必须在主机级别预先分配池的大小。太小PostgreSQL 无法使用它。太大你就浪费了其他容器无法触及的物理内存。这个池是静态的更改它意味着停止容器调整主机配置然后重新启动。在 Docker 中你需要在容器启动之前在主机上设置vm.nr_hugepages这需要对主机的 root 访问权限。在 Docker Desktop 上情况更糟因为你根本无法控制底层的 Linux 虚拟机。在 Kubernetes 中节点必须在 kubelet 能够将大页宣传为可调度资源之前预先分配大页。你在 Pod 规范中声明hugepages-2Mi或hugepages-1Gi但节点必须首先准备好池。在托管节点池上EKS、GKE、AKS你通常根本无法控制节点级别的内核配置。从 Pod 内部更改 THP 设置需要将主机的/sys挂载为卷或者部署一个特权的 DaemonSet这两种方法大多数集群管理员都不会批准。这一点的重要性超出了 Linux 7.0 的故事。使用大缓冲区池和 4KB 页面运行 PostgreSQL 一直是一个性能问题。Linux 7.0 事件只是以一种戏剧性的方式使其变得可见。如果你的 PostgreSQL 在容器中运行并且你无法在主机级别控制 THP 或大页那么你已经在损失性能了。行业已经严重倾向于容器化部署但尚未完全解决这个问题。Linux 社区的解决方案rseq几十年来PREEMPT_NONE充当了 PostgreSQL 的“请勿打扰”标志确保一个线程可以完成其工作而不被打断。Linux 7.0 移除了这个标志。虽然新的“懒惰”模式试图保持礼貌但如果线程在错误的时刻被暂停它会引入一定程度的不确定性可能将一个 20 纳秒的锁变成一个毫秒级的瓶颈。可重启序列 (rseq)是一种 Linux 内核机制允许用户空间代码向内核发出信号表明它正处于关键部分因此内核会延迟抢占直到锁被释放带 rseq 前后对比没有 rseq内核盲目抢占有了 rseq它能识别关键部分标志并等待问题不在于前进的方向。问题在于移除PREEMPT_NONE和引入rseq发生在同一个版本中两者之间没有过渡期。淘汰某样东西的正常方式是让新方法 alongside 旧方法一起发布弃用旧方法给人们时间迁移然后移除它。这一步被跳过了。内核团队提出的官方解决方案是采用可重启序列 (rseq) 来缓解这些性能衰退。然而有一个问题必要的切片扩展在 Linux 7.0 中默认未启用。它需要一个使用CONFIG_RSEQ_SLICE_EXTENSION和EXPERT1标志编译的内核。对于使用标准发行版的绝大多数 DBA 和 DevOps 工程师来说这使得“正确”的修复实际上无法实现。正如俗话所说这就像被告知在有人拿走梯子时紧紧抓住你的刷子。你实际上应该怎么做在采取任何行动之前使用你自己的工作负载和你自己的配置进行基准测试。在 96 核 ARM 机器上故意禁用大页的合成pgbench结果不能代表你的生产系统。如果你控制你的主机并且已经启用了大页或 THP升级到 Linux 7.0 并进行测量。你可能根本看不到任何性能衰退。如果你的主机上既没有启用大页也没有启用 THP在考虑内核升级之前先启用其中一个。对于显式大页在主机上设置vm.nr_hugepages并在postgresql.conf中设置huge_pages try。对于 THP在主机上设置transparent_hugepagealways。这两种方法都解决了底层的缺页错误问题。无论 Linux 7.0 如何这都是很好的建议。如果你在容器中运行 PostgreSQL并且无法在主机级别控制 THP 或大页请注意这对于大缓冲区池来说是一个普遍的性能问题。值得向管理你基础设施的人提出这个问题并且值得在你的部署架构选择中考虑进去。如果你使用的是搭载 Linux 7.0 的 Ubuntu 26.04 LTS不要恐慌。测试你实际的工作负载。如果你看到性能衰退首先检查你的大页配置。来源:Salvatore Dipietro 在 Linux 内核邮件列表上的讨论Hacker News 讨论TLB (Translation Lookaside Buffer)是 CPU 的一个缓存用于存储最近的虚拟内存到物理内存地址的转换。当 CPU 需要访问内存时它首先检查 TLB。如果转换不在那里“TLB 未命中”它必须遍历页表来找到物理地址这明显更慢。使用 4KB 页面和一个非常大的缓冲区池TLB 很快就会填满未命中变得频繁。更大的页面减少了 TLB 中需要的条目数量从而显著降低了未命中率。[↩︎]大页 (Huge Pages)也称为 HugeTLB 页面是一种 Linux 机制用于预先分配大的内存页面通常是 2MB 或 1GB而不是默认的 4KB。它们必须在使用前显式预留内核在启动时或通过vm.nr_hugepages预留一个池应用程序显式请求它们。PostgreSQL 通过postgresql.conf中的huge_pages try|on|off默认是try支持这一点。由于池是预先分配并锁定在内存中的大页不能被换出并且在初始分配后不会发生缺页错误。[↩︎]透明大页 (THP)是一种不同的机制。它不需要显式预分配内核会在后台自动将一组 4KB 页面提升为更大的页面对应用程序透明。不需要更改postgresql.conf。权衡之处在于可预测性较低内核后台对页面的提升和降级有时可能会导致延迟峰值。THP 通过/sys/kernel/mm/transparent_hugepage/enabled进行系统范围的控制这是一个对主机全局的 sysfs 路径不属于任何 Linux 命名空间。[↩︎]Incus 暴露了limits.hugepages.[size]以通过 hugetlb cgroup 限制容器的大页使用量但这需要主机上提供 hugetlb cgroup并且主机大页池必须首先预先分配。请参阅 Incus 实例选项文档。[↩︎]这来自一个法国笑话一个疯子正在重新粉刷他的天花板就在他到达梯子顶端时他的同伙说“紧紧抓住你的刷子我要把梯子拿走了。” [↩︎]PostgreSQL Linux 性能管理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2525185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…