概述
PostgreSQL数据库是由基于文件系统物理文件建立的,在数据库的运行过程中,整套高效严谨的的逻辑管理着这些物理文件。通常叫这些物理文件为数据库。将这些物理文件、管理这些文件的进程、进程管理的内存 称为这个数据库的实例。
本文就来学习一下实例的这三个组成部分,目录、进程及内存结构的知识。
目录结构
软件安装目录
PostgreSQL数据库的软件目录通常是在/usr 目录下(也可自定义位置),使用pg_confg命令可以看到当前数据库的基本情况,也可以在环境变量中可以看到。最直接可以使用which命令看到
[postgres@stephen pgsql-11.2]$ which psql
/usr/pgsql/bin/psql
安装目录里的基本内容如下
[postgres@stephen pgsql-11.2]$ pwd
/usr/pgsql-11.2
[postgres@stephen pgsql-11.2]$ ll
total 16
drwxr-xr-x 2 postgres postgres 4096 Apr 17 16:44 bin
drwxr-xr-x 6 postgres postgres 4096 Mar 15 16:15 include
drwxr-xr-x 4 postgres postgres 4096 Mar 15 16:15 lib
drwxr-xr-x 6 postgres postgres 4096 Mar 15 16:15 share
其中各个目录里的内容及用途:
- bin:二进制可执行文件,是PG数据库的所有相关命令所在,为方便使用需设置到环境变量中
- include:头文件目录
- lib :动态库目录,PostgreSQL运行所需要的动态库都在此目录下
- share:放有文档和配置模板文件,一些拓展插件的SQL文件在此目录下的extension中
数据目录
一般在postgres用户使用PGDATA指向数据目录,在初始化完成后,会在此目录中生成各种目录和文件。
文件有:
- postgresql.conf:数据库实例的主配置文件,基本上数据库的所有配置参数都在此文件中
- pg_hba.conf: 认证配置文件,配置了允许哪些IP主机可以访问数据库
- postgresql.auto.conf:也是配置文件,只能配置使用alter命令生效的参数
- pg_ident.conf:"ident"认证方式的用户映射文件
目录有:
- base:默认表空间的位置
- global:一些共享系统表的目录
- pg_wal:wal日志存储的目录
- pg_stat_tmp:统计信息的存储目录
- pg_twophase:使用两阶段提交功能时分布式事务的存储目录
- pg_log:日志文件,需要注意的是此log文件目录名是根据自己参数设置生成命名的
表空间
PostgreSQL中最大的存储单元就是表空间,数据库中创建的对象都是保存在表空间中,例如表和索引。在创建数据库对象时,可以指定数据库的表空间
初始化数据库成功后会生成以下两个表空间
postgres=# \db
List of tablespaces
Name | Owner | Location
------------+----------+----------
pg_default | postgres |
pg_global | postgres |
(2 rows)
其中pg_global 在数据目录的global文件中,它用来保存系统表。pg_default 表空间的物理文件位置在数据目录中的base目录。是template0和template1数据库的默认表空间,我们在创建数据库时,默认是从template1数据库进行克隆。因此除非特别指定了新建数据库的表空间,默认使用的是pg_default表空间
我们也可以自己创建表空间,步骤如下:
先自己使用postgres用户创建一个目录
[postgres@stephen pgdata]$ mkdir tablesapce_test
[postgres@stephen pgdata]$ pwd
/pgdata
在数据库中创建表空间
postgres=# create tablespace mytest location '/pgdata/tablesapce_test';
WARNING: tablespace location should not be inside the data directory
CREATE TABLESPACE
postgres=# \db
List of tablespaces
Name | Owner | Location
------------+----------+-------------------------
mytest | postgres | /pgdata/tablesapce_test
pg_default | postgres |
pg_global | postgres |
(3 rows)
再创建表的时候可以指定表空间
postgres=# create table table1(id int,name text) tablespace mytest;
CREATE TABLE
进程结构
PostgreSQL是一个多进程的应用程序,每一个用户连接,都会分配到一个用户进程。数据库启动时会启动若干进程,如下
[postgres@stephen ~]$ ps -ef|grep postgres
postgres 1077 1 0 11:58 pts/0 00:00:00 /usr/pgsql-11.2/bin/postgres
postgres 1078 1077 0 11:58 ? 00:00:00 postgres: logger
postgres 1080 1077 0 11:58 ? 00:00:00 postgres: checkpointer
postgres 1081 1077 0 11:58 ? 00:00:00 postgres: background writer
postgres 1082 1077 0 11:58 ? 00:00:00 postgres: walwriter
postgres 1083 1077 0 11:58 ? 00:00:00 postgres: autovacuum launcher
postgres 1084 1077 0 11:58 ? 00:00:00 postgres: archiver last was 000000010000000000000023
postgres 1085 1077 0 11:58 ? 00:00:00 postgres: stats collector
postgres 1086 1077 0 11:58 ? 00:00:00 postgres: logical replication launcher
守护进程postmaster
守护进程postmaster,及上面的 /usr/pgsql-11.2/bin/postgres进程,它的主要职责是:
- 数据库的启停
- 监听客户端连接
- 为每个客户端连接fork单独的postgres服务进程
- 当服务进程出错时进行修复
- 管理数据文件
- 管理数据库运行相关的辅助进程
当客户端调用接口像数据库发起连接请求,守护进程postmaster会fork单独的服务进程postgres 为客户端提供服务,此后由postgres服务进程为客户端执行各种命令,客户端也不需要postmaster进行中转,直接与服务进程postgres进行通讯。如下,另开几个窗口并进入数据库中,会出现服务进程
postgres 1167 1077 0 11:58 ? 00:00:00 postgres: postgres postgres [local] idle
postgres 1536 1077 0 13:46 ? 00:00:00 postgres: postgres postgres 192.168.56.101(53611) idle
日志进程 logger
PostgreSQL的默认日志是关闭的,所以缺省情况下,是没有这个进程的。但是一般情况下,我们都会打开这个参数。日志是我们日常运维的重要工具。在配置文件中将参数logging_collect 设置为on,打开日志收集,主进程就会启动logger日志进程
该进程会收集所有其他的进程stderr输出,并将这些输出写入到文件中形成日志。在配置参数中,可以自由的选择每个文件的大小及收集的日志策略。用户可以根据自己的需要自行配置
后台写进程 background writer
在PostgreSQL中,Bgwriter辅助进程是把共享内存中的脏页写到磁盘上的进程。当往数据库中插入或更新数据时,并不是会马上写到数据文件中,而是先放在共享内存中。Bgwriter辅助进程可以周期性地把内存中的脏数据刷新到磁盘中。刷脏数据的既不能太快,也不能太慢。
有点类似mysql的master thread和page cleaner thread的功能。当然此功能也可以通过一些参数进程自定义设置
预写日志 walwriter
所谓wal日志,即write ahead log,在一些较低的版本中,也称为xlog。预写的意思就是在修改数据之前,必须要把这些修改操作记录到磁盘中,这样后面更新实际数据时,就不要把数据持久化到文件中了。即使机器突然宕机或数据库异常退出导致一部分数据没有及时的刷新到磁盘。在数据库重启后,通过读取wal日志,并把最后一部分wal日志重新执行一遍,就可以恢复宕机时的状态。
wal现在默认保存在wal_log文件夹中,该目录会产生多个wal日志,不需要的wal日志会被覆盖掉
归档进程 archive
上面我们刚刚提到,不需要的wal日志是会被覆盖掉的,但是对于严谨的dba来说,只要有足够的硬盘,就绝对不会丢弃一点数据,谁也不知道有没有可能会需要他们。所以,PostgreSQL提供了日志归档功能
默认不是开启的,需要去手动开启,在配置文件中将archive_mode设为on,就会开启此进程。
但是详细的归档方案,需要自己在文件中设置
自动清理 autovacuum
在PostgreSQL数据库中,对表进行delete后。不会立即删除数据,并且在更新数据时,也不会在旧的数据上进行更新,而是生成一行新数据,旧的数据被标志删除状态,只有在没有并发的其他事物读到这些旧数据时,它们才会被清楚掉。这个清楚工作就是由autovacuum进程来完成的
PostgreSQL的mvcc就是使用这个特点完成的,和其他的数据库有一些区别
checkpointer 与 stats collector
checkpointer 是数据库的检查点进程
stats collector 主要做数据的统计收集工作,收集的信息主要用于查询优化代价评估
内存结构
共享内存 share_buffer
PostgreSQL启动后,会生成一块共享内存,共享内存主要是用于数据块的缓冲区,以便提高读写性能。wal日志的缓冲区和clog缓冲区也位于共享内存中。除此之外,一些全局信息也保存在共享内存中,如进程信息,锁信息
一般情况下,share_buffer 值不需要设置的很大,推荐值为是1/4物理内存
postgres=# show shared_buffers;
shared_buffers
----------------
128MB
(1 row)
本地内存
后台服务进行除了访问共享内存外,还会申请一些本地内存,以便暂存一些不需要全局存储的数据,一般分为以下几类:
- 临时缓冲区:用于访问临时表的本地缓冲区
- work_mem :内部排序聚合操作和hash表在使用临时磁盘文件时使用的内存缓冲区,需要关注的是:每个排序操作都会消耗一个work_mem内存,并不是一个SQL消耗一个,因此,当您的系统中有大量的排序时,此值可适当调小,防止内存用尽
- maintenance_work_mem:维护操作使用的内存