背景

不知道从何时开始,数据库空载时的性能消耗越来越高,当业务高峰期,CPU 和内存都处于高负载的情况下,观看 AWS 的监控,发现负载空载时占用很高。

并且占用较高的 Top5 分为为:

autovacuum: VACUUM ANALYZE pg_catalog.pg_attribute
autovacuum: VACUUM ANALYZE pg_catalog.pg_type
autovacuum: VACUUM ANALYZE pg_catalog.pg_depend
autovacuum: VACUUM ANALYZE pg_catalog.pg_class
autovacuum: VACUUM ANALYZE pg_catalog.pg_index

由上面的 Top5 可以得知,目前数据库的负载较高,都是由于 PgSql 系统表的 VACUUM 导致的,但是,为什么会出现这种情况呢?我们一起来慢慢解决这个问题吧!

问题排查

排查方向

VACUUM 是 PgSql 的一种垃圾回收机制,主要用于清理数据库中的不再需要的行(也称为“死亡行”或“dead tuples”),并且它回收这些行占用的空间。VACUUM操作还更新数据库的统计信息,这对于查询优化器来说非常重要。

如果 VACUUM 太慢,则有可能有以下几个原因:

  • 大容量数据:如果数据库非常大,VACUUM操作可能需要很长时间来完成,这会增加系统负载。
  • 高事务量:在高事务量的系统中,频繁的更新、插入和删除操作会产生许多不再需要的行,导致VACUUM工作量增加。
  • 不频繁的清理:如果长时间没有运行VACUUM,会导致数据库中积累大量的死亡行,需要更长时间来清理。

因为当前数据库集群都处于业务的低谷期,所以基本上没有啥负载,所以高事务量 可以排除,而数据库一直在频繁的执行清理任务,所以问题基本上可以锁定到大容量数据!

谁占用了空间?

因此,我们首先从数据表的空间占用上面进行问题排查!

我们可以使用 [[维护相关#数据表统计#数据表空间占用大小 | 数据表空间占用大小统计]] 相关 SQL:

SELECT
relname,
PG_SIZE_PRETTY(PG_TOTAL_RELATION_SIZE(oid)) AS total_size,
PG_SIZE_PRETTY(PG_RELATION_SIZE(oid)) AS relation_size,
*
FROM
pg_class
WHERE
relname LIKE 'pg_%'
AND relname NOT LIKE 'pg_toast_%'
ORDER BY
PG_TOTAL_RELATION_SIZE(oid) DESC
LIMIT 100
;

下面是返回的结果信息:

relname total_size relation_size
pg_attribute 32 GB 23 GB
pg_attribute_relid_attnam_index 5615 MB 5613 MB
pg_class 4303 MB 2877 MB
pg_attribute_relid_attnum_index 3595 MB 3594 MB
pg_depend 3584 MB 1616 MB
pg_type 3030 MB 2092 MB

上面 pg_attribute 总大小(数据表+索引)为:32 GB,因此,基本上可以判断,数据库的负载变高,是由于 pg_attribute 系统表导致的!

pg_attribute

那么问题来了,pg_attribute 到时候是什么数据表呢?

以下是 AI 助手 Kimi 给出的解答:

在PostgreSQL数据库中,pg_attribute是一个系统目录表,它存储了关于表列的信息。每个表的列都有相应的行记录在这个表中,包括系统表和用户定义的表。

pg_attribute表是PostgreSQL中众多系统目录表之一,它们为数据库中的各种对象提供了元数据。通过查询这些系统表,你可以获得关于数据库结构和配置的详细信息。

简而言之,它是一张 pgsql 的元数据信息表,存储 pg 数据库中的各个表字段的定义信息。

理论上,一个数据库中的数据表即使再多,它的元数据信息也不可能超过 30 GB,因此,我们接下来的排查方向,是要找出为什么 pg_attribute 数据表这么大!

数据膨胀

在我将此问题在网络上进行搜索的时候,一个新的名词出现在我的眼前:数据膨胀

PostgreSQL 数据膨胀是指数据库中的数据文件大小超出了实际存储数据所需的大小。这可能会导致存储空间的浪费,并且可能影响数据库的性能。以下是一些可能导致 PostgreSQL 数据膨胀的原因以及相应的解决方法:

  • 索引膨胀

    • 原因:随着数据的更新和删除,索引可能会变得“膨胀”,特别是对于B树索引。
    • 解决方法:定期重建索引可以减少膨胀。可以使用REINDEX命令来实现。
  • 表膨胀
    • 原因:表中的数据更新和删除操作可能导致表变得碎片化,从而增加表的物理大小。
    • 解决方法:使用VACUUM FULL命令来压缩表并回收空间。但请注意,这将创建一个新的表并重置统计信息。
  • 长事务
    • 原因:长时间运行的事务会锁定行,导致VACUUM不能回收空间。
    • 解决方法:避免长时间运行的事务,或者使用事务 ID 来限制事务的持续时间。
  • 未及时清理删除的数据
      • 原因:删除数据后,如果VACUUM没有运行,那么空间不会被回收。
    • 解决方法:定期运行VACUUM(或使用autovacuum)来清理不再需要的行。
  • 系统表膨胀
    • 原因:系统表,如pg_attribute,可能会因为存储了大量的元数据而变得庞大。
    • 解决方法:审查系统表的使用,移除不必要的元数据。

通过对上面造成数据膨胀的原因进行排查,最后锁定了最重要的两条:

  • 重复创建临时表:公司的很多业务涉及到 批量更新 ,为了使批量更新的速度更快,因此使用了 临时表方案 方案,重复执行 CREATE TEMP TABLE AS SELECT * FROM TABLE ,导致 pg_attribute 的数据一直处于上升的阶段。
  • 长事务:数据库的数据需要实时同步至数据仓库,同步是采用的 Flink-CDC 实时同步至 StarRocks,Flink-CDC 在同步阶段,会默认打开一个复制槽,当复制槽的 WAL 日志未被订阅者消费的时候,会存在一个长事务!

问题源头

下面,我来进行一个复盘,来说明为什么 pg_attribute 为什么会发生数据膨胀!

业务系统时时刻刻在执行 CREATE TEMP TABLE 命令,因此 pg_attribute 的数据会频繁的进行数据的插入和删除,正常情况下,及时 PgSql 的 VACUUM 会自动将删除的数据从磁盘中移除。

但是,因为数据库的数据需要同步至 数据仓库 ,因此使用了 Flink-CDC 进行同步,Flink-CDC 会开启一个复制槽,正常运行的情况下, Flink-CDC 会实时消费复制槽中的 WAL 日志,如果 Flink-CDC 同步任务关闭,但是又未关闭复制槽,复制槽为了保证订阅者数据完整性,会自动记录 FLink-CDC 上一次消费的位置,方便 Flink-CDC 下一次重启,重新监听 WAL 日志。

为了保证 WAL 日志的完整性,因此 PgSql 需要开启一个长事务,防止 PgSql 数据库的 VACUUM 把数据从磁盘清除。

所以,pg_attribute 数据表的数据因为长事务的原因,一直未被 VACUUM,所以导致数据表一直处于膨胀阶段,而因为 pg_attribute 是系统表,假如执行 VACUUM FULL pg_attribute ,将会锁全库,因此即使当后续事务关闭了,pg_attribute 的空间也无法得到正常的释放!

解决方案

停止创建临时表

因为系统一直在创建临时表,所以系统一直在对 pg_attribute 表进行 VACUUM ,假如 pg_attribute 的数据不再更新,那么就不会触发数据库的 VACUUM 了!

此方法治标不治本,只是避免了频繁执行 vacuum pg_attribute,从而减小系统负载

执行 VACUUM FULL

执行 vacuum full pg_attribute,但是此方案会锁全库,因此执行的时候,必须停服执行,对业务的影响较大。

PGSQL数据膨胀问题排查的更多相关文章

  1. 以elasticsearch-hadoop 向elasticsearch 导数,丢失数据的问题排查

    实际这是很久之前的问题了,当时没时间记录 这里简单回顾 项目基于 数据架构不方便说太细,最精简的 somedata-> [kafka]->spark-stream->elastics ...

  2. 数据库char varchar nchar nvarchar,编码Unicode,UTF8,GBK等,Sql语句中文前为什么加N(一次线上数据存储乱码排查)

    背景 公司有一个数据处理线,上面的数据经过不同环境处理,然后上线到正式库.其中一个环节需要将数据进行处理然后导入到另外一个库(Sql Server).这个处理的程序是老大用python写的,处理完后进 ...

  3. InnerJoin分页导致的数据重复问题排查

    2016年8月9号美好的七夕的早上,我精神抖擞地来到公司.一会之后,客服宅宅MM微信我,说一个VIP大店铺订单导出报表中一个订单有重复行.于是,我赶紧开始查探问题所在.经过一天的反复仔细追查(当然还包 ...

  4. 【Spark调优】数据倾斜及排查

    [数据倾斜及调优概述] 大数据分布式计算中一个常见的棘手问题——数据倾斜: 在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或j ...

  5. Hive数据导入HBase引起数据膨胀引发的思考

    最近朋友公司在做一些数据的迁移,主要是将一些Hive处理之后的热数据导入到HBase中,但是遇到了一个很奇怪的问题:同样的数据到了HBase中,所占空间竟增长了好几倍!详谈中,笔者建议朋友至少从几点原 ...

  6. Mysql 和 Postgresql(PGSQL) 对比

    Mysql 和 Postgresql(PGSQL) 对比 转载自:http://www.oschina.net/question/96003_13994 PostgreSQL与MySQL比较 MySQ ...

  7. Redis性能问题排查解决手册(七)

     阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_commands_processed 延迟时间 内存碎片率 回收key 总结 性能相关的数据指标 通过Red ...

  8. Redis性能问题排查解决手册

    转自:http://www.cnblogs.com/mushroom/p/4738170.html 阅读目录: 性能相关的数据指标 内存使用率used_memory 命令处理总数total_comma ...

  9. Spark性能优化之道——解决Spark数据倾斜(Data Skew)的N种姿势

    原创文章,同步首发自作者个人博客转载请务必在文章开头处注明出处. 摘要 本文结合实例详细阐明了Spark数据倾斜的几种场景以及对应的解决方案,包括避免数据源倾斜,调整并行度,使用自定义Partitio ...

  10. 干货!一次kafka卡顿事故排查过程

    由于一次功能上线后,导致某数据量急剧下滑,给我们紧张的呢!排查过程也是个学习过程(这其中有大部分是领导们的功劳,不过分享给大家应该也不犯法吧,ᐓ) 1. 确认问题的真实性? 被数据部门告知,某数据量下 ...

随机推荐

  1. 进程间通信-POSIX 信号量

    POSIX 信号量 POSIX 信号量是一种 POSIX 标准中定义的进程间同步和互斥的方法.它允许进程之间通过信号量来实现临界区的互斥访问,从而避免竞争条件和死锁等问题. 信号量的P.V操作: P ...

  2. Boost库简单介绍

    c++ boost库官网 https://www.boost.org/ 官网最新版文档说明 https://www.boost.org/doc/libs/1_70_0/ Boost库是一个可移植.提供 ...

  3. Nuxt的SEO实践

    第9章:Nuxt的SEO实践 1. 引言 Nuxt框架在SEO方面的优势主要体现在以下几个方面: 服务器端渲染(SSR): Nuxt默认支持SSR,这意味着搜索引擎爬虫可以直接看到完整的页面内容,而不 ...

  4. ChatGPT 相关资料

    ChatGPT是基于GPT-3.5的语言模型且并未开源.对ChatGPT的资料搜索主要来自于兄弟模型InstrucGPT的相关资料. 相比较于InstrucGPT,ChatGPT采用多轮对话形式,符合 ...

  5. 几种简单的springboot启动后启动一条死循环线程方式

    前言 之前有测试 # 启动类加 @EnableAsync # 方法上加注解 @Async @PostConstruct 但是依旧会卡主主线程,所有另辟蹊径 第一种 在启动类上加注解 @EnableAs ...

  6. 「Log」2023.8.18 小记

    序幕 七点到校,博客整理一下,补全目录. 写 AC 自动机练习题. \(\color{blueviolet}{P3966\ [TJOI2013]\ 单词}\) 挺板的,每个模式串当匹配串统计一遍答案即 ...

  7. go 进阶训练营 微服务可用性(上) 笔记

    隔离 本质上是对系统和资源进行分割,从而实现当系统故障时能限定传播范围和影响范围,即发生故障后只有出问题的服务不可用,保证其他服务仍然可用. 服务隔离 动静隔离 mysql 表中的bufferpool ...

  8. 看PHP7底层源码与设计 读后感

    对PHP的理解 读完这本书以后,发现自己好像不会PHP,自己知识PHP代码的搬运工,对数组的实现,内存管理,生命周期,垃圾回收,面向对象,Zend虚拟机这些知识点,这些都不知道,现在也说不上来,具体的 ...

  9. 揭秘如何用Monaco Editor打造功能强大的日志查看器

    Monaco Editor 是一个基于浏览器的代码编辑器,由 Microsoft 开发,是 Visual Studio Code 的核心编辑器组件.为用户提供了一个功能丰富.性能优异的代码编辑环境,常 ...

  10. HarmonyOS应用一键置灰指南

    一键置灰通常应用于如下场景 1. 重大悼念活动: 在国家发生重大灾难.事故或举行悼念日等特殊时期,为了表达对逝者的尊重和哀悼,许多 APP 会将界面置灰.例如,在一些地震.空难等灾难事件发生后,以及全 ...