更多"C/C++、PostgreSQL、编译原理、计算机原理、TCP/IP、数据结构&算法、Linux编程”等技术文章更新于公众号: 君子黎


1. 系统架构

    在【PostgreSQL教程】· 源码编译安装PostgreSQL 一文中,对PostgreSQL作过简要介绍,它是世界上最为先进的开源关系型数据库。专为可扩展性和自定义而设计的,它支持ANSI/ISO兼容的SQL(强烈符合ANSI-SQL:2008标准规范)。并且它还具有良好的可靠性、可移植性、可伸缩性以及安全性。

    PostgreSQL使用多进程模式的客户端/服务器体系结构。客户端将请求发送到PostgreSQL服务器,之后PostgreSQL服务器解析客户端下发的具体请求内容,并进行处理、响应。在这种情况下,典型的应用程序客户端和服务器位于不同的主机上。在客户端与服务器之间使用TCP/IP协议或是Linux套接字(AF_UNIX)进行通行。在数据库的内部,主要是由一些后台进程、共享内存和数据文件组成。其系统的基本架构原理如下图所示:
在这里插入图片描述

1.1 C/S通信模式

    它通过C/S的模式提供服务,通常PostgreSQL数据库会话由以下两个进程(程序)组成。

    · 服务端进程

    该进程管理数据库的库文件,包括视图、索引、表、日志等等,并且它接收客户端的连接,并代表客户端来操作数据库,这个服务进程是postgres。

    · 客户端(前端)应用程序

    即PostgreSQL数据库操作的客户端应用程序,它可能是:libpq封装的应用程序、字符界面工具(psql)、图形界面(pgAdmin)或通过网页访问数据库的Web程序等等。总之,客户端应用程序是多种多样的。如下图所示:

在这里插入图片描述

1.2 PostgreSQL服务器进程类型

    通常情况下,对协作管理一个数据库集群的多个进程的集称为“PostgreSQL服务器”。在PostgreSQL中,进程类型大致上可分为以下三类,分别是:

    · Postmaster(守护进程)

    · Background Process(后台进程)

    · Backend Process(后端进程)

1.2.1 postmaster守护进程

    当执行附加-start选项参数的pg_ctl程序命令时,postgres服务器将启动,它是PostgreSQL服务启动过程中的第一个进程。同时它也是PostgreSQL数据库服务器中所有进程的父进程,在早期的PostgreSQL版本中,该父进程称为“postmaster”(备注:除非特殊声明,否则后序所有文章中都将该父进程称呼为postmaster)。当该进程启动后,将执行一系列的初始化操作,比如初始化环境变量、全局遍历、安装信号捕捉函数、在内存中分配一个共享内存区域、fork()各种辅助后台进程(checkpointer、logger),并负责后台进程的管理。如下图所示:
在这里插入图片描述

    同时它将等待客户端的连接请求。默认配置下,PostgreSQL服务器监听5432的端口。对于一台服务器,可以在上面同时运行多个PostgreSQL数据库服务器,此时,应该将各PostgreSQL服务器修改为监听不同的端口号。

    当客户端向postmaster服务器发起TCP连接请求时候,首先它会发起身份认证消息,postmaster守护进程会根据配置(pg_hba.conf)的认证方法对该客户端请求进行相应的检验,当身份认证校验通过之后,会新fork()一个后端进程(postgres),之后该postgres将负责处理对应的连接客户端的所有查询以及其他操作。其请求连接详细过程如下所示:
在这里插入图片描述

1.2.2 Background Process 后台进程

    PostgreSQL的后台进程有check pointer、background write、walwriter、autovacuum launcher、stats collectorlogical replication launcher。每个后台进程负责完成自己专属的逻辑业务处理,下面将详细说明每个后台进程的功能。

    ==· check pointer==

    检查点是一个强制性的过程。一旦用户更改了数据(这些数据已经在缓冲区中可用),该缓冲区就是脏的。用户提交的更改并不意味着该更改已经写入到数据文件中,真正更改写入到磁盘数据文件中的任务是由check pointer后台进程完成的。如下图所示:
在这里插入图片描述

    它将所有脏页从内存写入到磁盘上的表和索引文件,并清除shared_buffers区域,将页面标记为干净的。此外,它还将到目前为止的预写日志标记为已应用。和check pointer主要相关联的两个参数分别是checkpoint_segments 、checkpoint_timeout 。如果将checkpoint_segments 设置得过低,会导致可用的段很快被填充满,并且check pointer也会运行很频繁;同样,若将checkpoint_timeout 参数设置的过低,也会导致check pointer进程频繁地工作运行。参数过低的设置将带来的最直接影响就是磁盘吞吐量过大。另一方面,如果我们将这checkpoint_timeout 、checkpoint_segments 参数的值设置得过大,则会出现check pointer进程运行频率很低的情况。这在某些写操作较多的系统中,可能会导致检查点期间出现异常的高I/O峰值,从而影响其他查询等操作的性能。
check pointer将会发生在以下几种情形中出现:
pg_start_backup、CREATE DATABASE、pg_ctl stop|restart、pg_stop_backup、issue of commit、pages is dirty等。

    ==· background write==

    background write后台写进程的功能是根据算法将shared_buffers中的特定脏(新的或是修改过的)数据写入到磁盘文件中。备:check pointer检查点进程则是将缓冲区中的所有脏数据写入到磁盘文件中去。由于有专门的进程负责写缓冲区脏数据,因此,处理客户端查询的服务器(postgres)进程很少或从不需要去等等写操作的发生。不过,后台写进程确实会导致I/O负载的整体净增加,因为虽然重复写入的页面可能每个检查点间隔只能写入一次,但是background write进程可能会多次写入它,因为在同一时间间隔中,它被弄脏了。
在这里插入图片描述

    ==· walwriter==

    前面提到过,当我们提交修改数据的请求时候,这些修改并不会立即被写入到磁盘文件。PostgreSQL对共享缓冲区中的数据块进行这些修改,然后将这些修改写入到WAL缓冲区。当(每次)提交事务时,更改(WAL缓冲区)会被刷新到WAL段。
与WAL相关的几个参数有:fsync、max_wal_size、wal_writer_delay。
其中fsync设置强制每个事务在每次提交之后写入磁盘。关闭此功能将提高性能,特别是针对一些批量上传操作;禁用fsync可能会导致严重的问题,比如电源断电或服务器奔溃时,数据一致性问题。

    在写操作较为频繁的系统中,过小的设置max_wal_size可能会导致性能损失、下降;而设置过高的max_wal_size将会显著地增加恢复时间。wal_writer_delay是walwriter进程活动轮之间的延迟,在每一个回合中,都将会把WAL写入到磁盘文件中。然后它休息wal_writer_delay毫秒,并不断重复此过程。注意:在许多系统中,将wal_writer_delay设置为10ms是个不错的选择。

    · logical replication launcher

    日志收集器进程,它捕获发送到stderr的日志消息,并将他们重定向到日志文件中。所有的后台进程、后端进程(postgres)以及postmaster守护进程所产生的活动信息都将被logical进程给记录下来。在【PostgreSQL教程】· SysLogger日志收集器工作原理 中有详细剖析过其初始化流程以及工作原理,同时在【PostgreSQL教程】· PostgreSQL配置管理日志(一) 一文中也详细讲解了与日志收集器logger进程相关的配置参数。

    ==· autovacuum launcher==

    和logger日志收集器进程一样,autovacuum进程是一个支持手动关闭/打开的后台进程,不过autovacuum进程默认是开启的,而logger日志收集器进程默认是关闭的。autovacuum进程将以前删除(或更新)的记录(行,元组)所使用的空间标记为可在表中重用的空间。它还有一个vacuum命令可以手动执行此操作。vacuum进程操作不会锁住表。

然而VACUUM FULL除了将空间标记为可重用外,还会删除之前已删除或更新的记录,并重新排序表数据,这需要使用独占锁。PostgreSQL服务会在服务处于非高峰、负载情况下,自动开启vacuum,vacuum会更新规划器使用的数据统计信息。

    ==· stats collector==

    stats collector统计收集器进程支持收集和报告有关服务器活动的消息,然后将这些信息更新给优化器(pg_catalog),优化器使用pg_catalog生成查询计划。收集器可以计算磁盘块和单行项中对表和索引的访问次数。它还跟踪每个表中的总函数,以及关于每个表的vacuum和analyze操作的信息。

    它还可以计算对用户定义函数的调用以及每次调用所花费的时间。它还支持报告其他服务器进程当前正在指向的确切命令。stats collector状态统计器通过临时文件将收集到的信息传递给其他PostgreSQL进程。默认情况下,这些文件存储在由stats_temp_directory参数命名的目录中,即pg_stat_tmp。为了获取更好的性能,可将stats_temp_directory指向基于RAM的文件系统中,从而降低物理I/O需求。

    当服务器完全关闭时候,统计数据的永久副本存储在pg_stat子目录中,这样在服务器重启时统计数据可以保留。

    在服务器启动时执行恢复(例如,在立即关机、服务器奔溃和时间点恢复点之后),所有统计计数器都将重置。
在这里插入图片描述

1.2.3 Backend Process 后端进程

    在1.3.1节中关于postmaster守护进程如何接收客户端的连接请求,作了比较详细的说明。简言之就是客户端的每个请求连接,postgmaster都会fork()一个postgres后端进程来进行处理。可打开的后端进程最大数目由postgresql.conf配置文件中的max_connections参数进行控制,默认值是100个。该参数可以通过修改postgresql.conf配置文件修改,也可通过执行系统命令ALTER SYSTEM来进行修改,详细修改过程请阅读【PostgreSQL教程】· 彻底搞清postgresql.auto.conf 与 postgresql.conf 之间的差异