理解PostgreSQL的体系结构

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: PostgreSQL可能是开源关系数据库市场中最先进的数据库。1989年首次发布,从此有了大量的改进和功能增强。根据db-engine统计,截止到目前,PostgreSQl在最常使用的数据库中,排名第四。

PostgreSQL可能是开源关系数据库市场中最先进的数据库。1989年首次发布,从此有了大量的改进和功能增强。根据db-engine统计,截止到目前,PostgreSQl在最常使用的数据库中,排名第四。

我们将会讨论PostgreSQL的内部结构,体系结构以及各种组件之间的交互。这篇文章将作为我们后续的PostgreSQL DBA博客系列文章的起点和组成。

PostgreSQL体系结构

PostgreSQL的物理结构非常简单。它是由共享内存(shared memory)和少量的后台进程以及数据文件组成。
image

共享内存(shared memory)

共享内存是指提供数据缓存和事务日志缓存的内存。在共享内存中最重要的组成部分是shared Buffer和WAL buffer(Write-Ahead Logging)

shared Buffer(共享缓冲区)

共享缓冲区的主要目的是最大限度的减少磁盘IO.为达到这个目的,必须要满足如下的这些要求

  • 需要快速访问非常大的缓冲区
  • 当多个用户同时访问并发生争用时,应该确保最小化争用。
  • 使用最频繁的数据块必须尽可能长时间的保存在缓冲区中。

WAL buffer(预写日志缓存)

WAL:Write-Ahead Logging 预写日志

WAL buffer 是一个临时存储数据更改的缓冲区,存储在WAL buffer 中的内容将在预定的时间点写入WAL文件。
从备份和恢复的角度,WAL buffer和WAL文件是非常重要的。

PostgreSQL 进程的类型

PostgreSQL有四种类型的进程

  • Postmaster(Daemon)进程
  • 后台进程(Background Process)
  • 后端进程(Backend Process)
  • 客户端进程(Client Process)

Postmaster 进程

Postgmaster进程是PostgreSQL启动的第一个进程。
负责实施恢复,初始化共享内存,并启动后台进程。
当客户端进程有链接请求时,负责创建后端进程。

image

如果使用pstree命令检查进程之间的关系,你会发现Postmaster是所有进程的父进程。(pstree命令并不显示进程的名称,为了解释清晰,我增加了进程的名称和参数)

image

后台进程(Background Process)

PostgreSQL操作所需的后台进程列表如下。

进程名称 角色作用
logger 将错误信息写入到日志文件中
checkpointer 每次触发检查点,缓冲区中修改过的数据会被写入到文件
writer 周期性的将缓冲区中修改过的数据写入到文件中
wal writer 将WAL缓冲区的数据写入到WAL文件中
Autovacuum launcher 如果参数配置为autovacuum开启,则负责创建autovacuum worker进程。 autovacuum守护进程的职责是对需要清理的表执行vacuum操作
archiver 当处于归档日志模式时,拷贝WAL文件到指定的目录
stats collector 收集会话执行信息(pg_stat_activity)和表的使用信息(pg_stat_all_tables)等数据库系统需要的统计信息

后端进程(Backend Process)

后端进程的最大数量取决于max_connections参数的设置,默认值是100。
后端进程执行用户的查询请求,然后传输结果。
执行查询操作需要一些特定的内存结构,我们称为本地内存。
与本地内存相关的主要参数

  • work_mem空间主要用来进行排序、位图操作、哈希连接、合并连接。默认值为4M。
  • Maintenance_work_mem空间主要用于Vacuum和创建索引。默认值为64M.
  • Temp_Buffers空间用户临时表,默认值为8M

客户端进程(Client Process)

客户端进程是指为每个后端用户连接分配的后台进程。通常,postmaster进程将创建一个子进程,该子进程专用于服务于用户连接。

数据库结构

当我们尝试理解PostgreSQL的数据库结构时,有如下这些重要的事情需要了解

与数据库相关的

  1. PostgreSQL由几个数据库组成,我们称之为数据库集群。
  2. 当initdb()被执行的时候,template0 , template1 , and postgres 数据库将被创建。
  3. template0 , template1是用户创建数据库时的模板数据库,其中包含了系统字典表。
  4. 在执行了initdb()后,template0 , template1中的表是相同的。然而,template1数据库能够创建用户所需的数据库对象。
  5. 用户数据库是通过克隆template1数据库创建的。

与表空间相关

  1. 在执行完initdb()后,表空间pg_default和pg_global则立即被创建。
  2. 创建表时如果不指定表空间,则表默认存储在pg_default表空间。
  3. 数据库集群级别管理的表存储在pg_global表空间中。
  4. pg_default表空间的物理位置是$PGDATAbase。
  5. pg_global表空间的物理位置是$PGDATAglobal。
  6. 一个表空间可以被多个数据库使用。此时,将在表空间目录中创建特定于数据库的子目录。
  7. 创建用户表空间将在$PGDATAtblspc目录中创建到用户表空间的符号链接。

与表相关

  1. 每个表对应三个文件

    • 一个是存储数据的文件,文件名是该表的OID
    • 一个是管理表空闲空间的文件,文件名为OID_fsm
    • 一个是管理表块可见性的文件。文件名是OID_vm
    • 索引没有_vm文件。也就是说,OID和OID_fsm由两个文件组成。

其他需要记住的

创建表和索引时的文件名是OID。OID和pg_class.relfilenode是相同的。
但是,当执行重写操作(Truncate、CLUSTER、Vacuum Full、REINDEX等)时,将更改受影响对象的relfilenode值,文件名也将更改为relfilenode值。您可以使用pg_relation_filepath ('< object name >')轻松地检查文件位置和名称。

实际操作

如果在initdb()之后查询pg_database视图,可以看到已经创建了template0、template1和postgres数据库。

postgres=# select oid,datname,datistemplate,datallowconn from pg_database order by 1;
  oid  |  datname  | datistemplate | datallowconn 
-------+-----------+---------------+--------------
     1 | template1 | t             | t
 13210 | template0 | t             | f
 13211 | postgres  | f             | t
 16394 | bucardo   | f             | t
(4 rows)
  • 通过datistemplate列,您可以看到template0和template1数据库是用于创建用户数据库模板的数据库。
  • datlowconn列指示是否可以访问数据库。不能访问template0数据库,同时数据库的内容也不能更改。
  • 为模板提供两个数据库的原因是,template0数据库是初始状态模板,template1数据库是用户添加的模板。
  • postgres数据库是使用template1数据库创建的默认数据库。如果在连接时没有指定数据库,则将连接到postgres数据库。
  • 数据库位于$PGDATA/base目录下。目录名是数据库的OID号。
[postgres@localhost base]$ ll 
总用量 48
drwx------. 2 postgres postgres 8192 7月  11 14:20 1
drwx------. 2 postgres postgres 8192 6月  28 13:49 13210
drwx------. 2 postgres postgres 8192 7月  11 14:20 13211
drwx------. 2 postgres postgres 8192 7月  11 14:21 16394

创建用户数据库

用户数据库由克隆template1数据库创建。要验证这一点,请在template1数据库中创建一个用户表T1。创建mydb01数据库之后,检查T1表是否存在。

postgres=# \c template1
You are now connected to database "template1" as user "postgres".
template1=# create table t1 (c1 integer);
CREATE TABLE
template1=# \c postgres
You are now connected to database "postgres" as user "postgres".
postgres=# create database mydb01;
CREATE DATABASE
postgres=# \c mydb01
You are now connected to database "mydb01" as user "postgres".
mydb01=# \d
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | t1   | table | postgres

image

pg_default 表空间

如果在initdb()之后查询pg_tablespace,可以看到已经创建了pg_default和pg_global表空间。

postgres=# select oid,* from pg_tablespace;
  oid  |  spcname   | spcowner | spcacl | spcoptions 
-------+------------+----------+--------+------------
  1663 | pg_default |       10 |        | 
  1664 | pg_global  |       10 |        | 
 16999 | tbs_test   |       10 |        | 
(3 rows)

pg_default表空间的位置是$PGDATAbase。这个目录中有一个按数据库OID划分的子目录

[postgres@localhost base]$ ls -l $PGDATA/base
总用量 60
drwx------. 2 postgres postgres 8192 7月  12 14:57 1
drwx------. 2 postgres postgres 8192 6月  28 13:49 13210
drwx------. 2 postgres postgres 8192 7月  11 14:20 13211
drwx------. 2 postgres postgres 8192 7月  11 14:21 16394
drwx------. 2 postgres postgres 8192 7月  12 14:59 17008

image

pg_global 表空间
pg_global表空间是用于存储要在“数据库集群”级别管理的数据的表空间。

  • 例如,与pg_database表类型相同的表无论是否从任何数据库访问,都提供相同的信息。
  • pg_global表空间的位置是$PGDATAglobal。

创建用户表空间

postgres=# create tablespace myts01 location '/data01';
CREATE TABLESPACE
postgres=# select oid,* from pg_tablespace;
  oid  |  spcname   | spcowner | spcacl | spcoptions 
-------+------------+----------+--------+------------
  1663 | pg_default |       10 |        | 
  1664 | pg_global  |       10 |        | 
 16999 | tbs_test   |       10 |        | 
 17010 | myts01     |       10 |        | 
(4 rows)

$PGDATA/pg_tblspc目录中的符号链接指向表空间目录。

[postgres@localhost ~]$ ls -l $PGDATA/pg_tblspc
总用量 0
lrwxrwxrwx. 1 postgres postgres 37 7月  12 13:39 16999 -> /usr/local/pgsql/data/tablespace_data
lrwxrwxrwx. 1 postgres postgres  7 7月  12 15:15 17010 -> /data01
[postgres@localhost ~]$ 

更改表空间位置

PostgreSQL在创建表空间时指定一个目录。因此,如果目录所在的文件系统已满,则不能再存储数据。要解决这个问题,可以使用卷管理器。但是,如果不能使用卷管理器,可以考虑更改表空间位置。操作顺序如下。

[postgres@localhost 13211]$ pg_ctl stop
waiting for server to shut down.... done
server stopped

[root@localhost 13210]# cp -rp /data01/PG* /data02

[root@localhost pg_tblspc]# chown postgres.postgres /data02

[root@localhost pg_tblspc]# ll
总用量 0
lrwxrwxrwx. 1 postgres postgres  7 7月  12 15:15 17010 -> /data01

[root@localhost pg_tblspc]# rm 17010

[root@localhost pg_tblspc]# ln -s /data02 17010

[postgres@localhost 13211]$ pg_ctl start

Note: 表空间在使用分区表的环境中也非常有用。因为可以为每个分区表使用不同的表空间,所以可以更灵活地处理文件系统容量问题。

什么是Vacuum?

Vacuum做了如下这些事

  1. 收集表和索引统计信息
  2. 重新组织表
  3. 清理表和索引无用的数据块
  4. 由记录XID冻结,以防止XID循环

1和2通常是DBMS管理所必需的。但是3和4是必要的,因为PostgreSQL MVCC特性

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
SQL 存储 缓存
PG内核解读-第2节PostgreSQL体系结构
本文整理自阿里云数据库开源社区Maintainer于巍(花名漠雪),在PostgreSQL数据库内核解读系列的分享。本篇内容主要分为三个部分: 1. PostgreSQL系统表 2. PostgreSQL初始化、启动、查询流程 3. PostgreSQL辅助进程
PG内核解读-第2节PostgreSQL体系结构
|
SQL 存储 缓存
【视频】PostgreSQL 体系结构 | 学习笔记
快速学习【视频】PostgreSQL 体系结构
120 0
【视频】PostgreSQL 体系结构 | 学习笔记
|
存储 SQL Cloud Native
直播预告 | PostgreSQL 内核解读系列第二讲:PostgreSQL 体系结构
本系列课程将面向DBA、高校学生、内核爱好者,介绍PG内核架构、各模块基本原理、用法、代码实现。希望通过课程学习,让没有内核经验的同学和DBA,也可以进行简单的特性开发,更深入理解PG配置和运行原理。本课程包含15个章节,系统化介绍PG架构、SQL引擎、执行引擎、存储引擎、并发控制、HA、分布式等核心技术原理和代码实现。
直播预告 | PostgreSQL 内核解读系列第二讲:PostgreSQL 体系结构
|
存储 关系型数据库 数据库
PostgreSQL体系结构
概述 PostgreSQL数据库是由基于文件系统物理文件建立的,在数据库的运行过程中,整套高效严谨的的逻辑管理着这些物理文件。通常叫这些物理文件为数据库。将这些物理文件、管理这些文件的进程、进程管理的内存 称为这个数据库的实例。
2969 0
|
关系型数据库 数据库 PostgreSQL
Postgresql数据库体系结构-进程和内存结构
数据库体系结构-进程和内存结构(Process and Memory Architecture) 进程结构 服务器进程postmaster后台工作进程后端进程 内存结构 本地内存区 work_memmaintenance_work_memtemp_buffers 共享内存区 shared buffer poolWAL buffercommit log 数据库启动过程 数据库连接过程 PostgreSQL是一个client/server架构rdbms,一个服务器上运行多个进程。
2151 0
|
存储 关系型数据库 数据库
Postgresql数据库体系结构-存储结构
PostgreSQL数据库体系结构-存储结构 存储结构 聚簇逻辑结构聚簇物理结构 聚簇数据库数据文件表空间数据文件内部结构tuple的读写方法 1、数据库聚簇逻辑结构(Logical Structure of Database Cluster) database...
6615 0
|
9月前
|
SQL Cloud Native 关系型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
742 1
|
9月前
|
数据可视化 关系型数据库 MySQL
将 PostgreSQL 迁移到 MySQL 数据库
将 PostgreSQL 迁移到 MySQL 数据库
1065 2
|
8月前
|
SQL 存储 自然语言处理
玩转阿里云RDS PostgreSQL数据库通过pg_jieba插件进行分词
在当今社交媒体的时代,人们通过各种平台分享自己的生活、观点和情感。然而,对于平台管理员和品牌经营者来说,了解用户的情感和意见变得至关重要。为了帮助他们更好地了解用户的情感倾向,我们可以使用PostgreSQL中的pg_jieba插件对这些发帖进行分词和情感分析,来构建一个社交媒体情感分析系统,系统将根据用户的发帖内容,自动判断其情感倾向是积极、消极还是中性,并将结果存储在数据库中。
玩转阿里云RDS PostgreSQL数据库通过pg_jieba插件进行分词
|
8月前
|
关系型数据库 测试技术 分布式数据库
PolarDB | PostgreSQL 高并发队列处理业务的数据库性能优化实践
在电商业务中可能涉及这样的场景, 由于有上下游关系的存在, 1、用户下单后, 上下游厂商会在自己系统中生成一笔订单记录并反馈给对方, 2、在收到反馈订单后, 本地会先缓存反馈的订单记录队列, 3、然后后台再从缓存取出订单并进行处理. 如果是高并发的处理, 因为大家都按一个顺序获取, 容易产生热点, 可能遇到取出队列遇到锁冲突瓶颈、IO扫描浪费、CPU计算浪费的瓶颈. 以及在清除已处理订单后, 索引版本未及时清理导致的回表版本判断带来的IO浪费和CPU运算浪费瓶颈等. 本文将给出“队列处理业务的数据库性能优化”优化方法和demo演示. 性能提升10到20倍.
597 4