一文看懂PostgreSQL内核(架构篇)

前言

pg作为世界上最好的开源数据库,不仅拥有超长的历史,赏心悦目的代码,还有百科全书般的文档,有问必答的活跃社区。作为数据库一哥的他,不仅在单机关系型数据库领域遥遥领先,而且在分布式领域也是开创了PGXC这一风格的架构,和Google Spanner争锋相对,可谓一时瑜亮。那么pg有什么魅力,我来简单介绍一下。

逻辑架构:

我们先来先看下PG的逻辑结构,这是最标准的关系型数据库,它是的这几个模块都是教科书上标准的数据库基本模块

  • 连接管理系统:主要是负责客户端对数据库系统的请求,对请求进行预处理和分发,CS架构

  • 编译执行系统:就是查询模块,负责将请求转化成计划树,就是所有支持SQL的数据库都有的解析、重写、优化、执行模块

  • 存储管理系统:主要负责存储和管理物理数据,支持多种索引:btree、hahs、GiST、GIN、BRIN,使用slotted page作为页的结构,自己维护了一套buffer机制

  • 事务系统:负责请求的事务ACID的支持,可以设置三种隔离级别RC、RR、SI,支持MVCC,支持大规模并发访问

  • 系统表:pg的元信息管理中心,是每个模块的中心枢纽。initdb就是在初始化系统表,虽然它这么重要,但其实就是一个普通表,用户可以随便去增删改查,但这种作死的行为肯定是会把数据库搞崩溃的。具体内容可以看官方文档:https://www.postgresql.org/docs/14/catalogs.html

    系统表需要经常访问,所以它理所当然是长期放在cache里,并且通过hash映射能够最快的进行查询。

在这里插入图片描述

进程架构

客户端可以通过多种方式连接pg(libpq、JDBC、ODBC),由客户端的库提供。客户端和pg进程是一对一的(process-per-connection),一个后端进程同一时间只能处理一条请求,整个pg应用需要多个连接才可以并发处理请求,即多个后端进程并发。

postmaster和postgres

pg采用了多进程架构,服务器守护进程postmaster是核心,它是一个中央协调进程,负责系统的初始化(分配共享内存,启动后台进程backend)和关闭server、授权。

管理客户端应用的连接,每一个新来的连接都需要postmaster分配一个postgres服务进程来提供服务。每个用户建立连接之后,postmaster会一次启动SysLogger(系统日志)、PgStat(统计数据)、AutoVacuum(自动清理)、WAL(预写日志)、BgWriter(后台写)等等进程来保证服务。实际上postmaster就像领导一样,它的工作就是把任务分配给它fork出来的postgres去干,自己就干一些监听调度的工作,领导怎么可能去干那些服务用户的脏活累活呢?

postmaster启动的辅助进程

  • 共享内存和信号库:因为是多进程架构,各个进程之间不会影响彼此,这种设计稳定性更好。但是各个进程之间通信的代价就比较高了,一般通过共享内存和信号进行通信,保证并发访问时数据的一致性。
  • SysLogger系统日志进程:生成系统日志信息
  • Bgwriter:周期性的把buffer里的脏页写进永久存储,LRU策略,支持checkpoint。当然pg也不完全依赖该进程把所有脏页落盘,其他进程也会去写
  • 静态收集器:不断收集静态的信息(表的访问信息和行数)
  • WAL写进程:周期性将WAL的数据flush到永久存储里,在多用户的环境里,许多事务的提交可以打包成一次fsync来完成。pg单独有一个进程去写WAL日志,是为了避免其他事务提交的时候才去落盘WAL,可以预先
  • PgArch WAL日志归档进程:除了WAL以外,pg还维护了一个进程对WAL文件在磁盘上的存储形式(Xlog文件)进行归档备份。如果不进行归档,则WAL日志文件会变得无限多,但是pg只会使用一个文件写wal,所以需要一个进程管理wal的历史记录
  • AutoVacuum进程:pg采用标记删除,不会立刻释放空间,所以需要额外的清理工作。自动清理包括一个Launcher监控进程和一个worker工作进程
  • PgStat统计数据收集进程:收集数据库系统运行中的统计信息,可以配置为off,以减轻cpu负荷
  • checkpoint进程:加速恢复

在这里插入图片描述

sql执行流程

最后我们用一个简单的查询,串起来之前讲过的所有模块。

SELECT name, age FROM users WHERE age > 30 ORDER BY age DESC LIMIT 10;
  1. 客户端发送 SQL 请求:客户端(libpq)

    建立连接:你的应用(如 Python/Java)使用 libpq(PostgreSQL 的客户端库)连接数据库。

    发送请求:发送 SQL 语句到服务器的 Postmaster 进程。

    分配postgres进程:服务器接受请求后,分配一个 Backend 进程(每个连接一个进程)。

  2. 连接管理:Postmaster(主进程)。

    监听客户端请求,创建新的 Backend 进程 处理请求。

  3. SQL 解析:解析器

    词法分析:将 SQL 拆解成关键字、标识符、运算符。

    语法分析:检查 SQL 是否符合 PostgreSQL 语法,构建解析树

  4. 查询重写:重写器

    如果查询涉及 视图(View)、规则(Rule),重写查询计划。例如,如果 users 是一个视图,PostgreSQL 会把它展开成底层的表查询。

  5. 查询优化:优化器,生成的执行计划可以通过explain查看

    成本估算(Cost-based Optimization):PostgreSQL 计算不同执行计划的 I/O、CPU、内存消耗,选择最优方案。

    索引优化:如果 age 列有索引,优化器会选择索引扫描(Index Scan)而不是全表扫描(Seq Scan)。

    排序优化:由于 ORDER BY age DESC,优化器会决定是否使用索引排序(Index Sort)或磁盘排序(External Sort)。

    LIMIT 优化:由于 LIMIT 10,优化器可能会 提前停止查询,减少不必要的计算。

  6. 执行计划执行:执行器

    通过 Seq Scan(全表扫描) 或 Index Scan(索引扫描) 读取数据。

  7. 存储层:Buffer Manager + WAL

    缓存数据:查询的数据首先在 共享内存(Shared Buffers) 里查找,如果没有才去磁盘读取。

    事务日志(WAL):如果 SQL 是 UPDATE/INSERT/DELETE,会先写 WAL 保证事务安全。

  8. 结果返回给客户端:Backend 进程

    PostgreSQL 将查询结果封装为 JSON 或二进制格式,返回给客户端。释放临时资源(如排序缓冲区)。

  9. 客户端收到结果,SQL 执行结束!

结语

本文从宏观介绍了pg的框架,很多细节会在之后的文章一一介绍,虽然文章开头把pg吹的天花乱坠,但是我们也可以通过pg的架构看到很多历史包袱,毕竟是一个发展30多年的数据库了。

比如采用多进程模型,导致高并发的场景中显得过于笨重了;只能使用heap table作为存储引擎,不支持很多优秀的开源存储引擎;没有考虑分布式的设计,分片、HA、多主的实现都需要借助其他插件来完成,但是插件局限性很大,不如原生架构做的好。

虽然 PostgreSQL 有历史包袱,但它仍然是世界上最强大的开源关系型数据库,很多大公司(Apple、Netflix、Reddit、GitHub)都在用它。随着 PG 的不断优化,它的这些“包袱”也在逐步被解决!


最后打个广告,了解开源时序数据库TDengine 更多内容欢迎访问:TDengine

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值