本文主要介绍Postgresql体系结构的配置文件和服务进程部分,内存区域和磁盘存储部分,欲知详情请看下节PostgreSQL体系结构(下)。
PostgreSQL是一种典型的客户端/服务端、多进程架构模型。主体是由一个守护监听进程Postmaster,若干个客户端应用程序(比如psql,navicat,DBeaver……)和若干个后端PostgreSQL进程(postgres,background writer,wal writer,checkpointer……)所组成。
整体上包括以下几个部分:
PostgreSQL数据库启动时会先启动一个主进程 postgres(9.3之前称为postmaster,9.3以后称为postgres server process),然后fork出一些辅助子进程(backend、backgroud相关进程),不同的辅助子进程负责不同的工作。当客户端请求访问时,客户端先与主进程创建连接并进行身份验证,身份验证成功后fork出一个子进程(服务进程)为这个连接服务。所以说PG数据库其实是一个多进程架构模型。
PostgreSQL 中的内存架构可以分为两大类,本地内存区域:由每个后端进程分配供自己使用。共享内存区域:由 PostgreSQL 服务器的所有进程使用。
1.1 配置文件
主配置文件:主要影响当前数据库实例的基本行为。比如允许的连接数,操作允许占用的最大内存数,归档模式,日志输出格式等等。当然这一切在数据库安装好时都有一个默认值,可以对这些数值进行符合需求的修改。存放在数据库集群的数据目录里。
#查看配置文件的位置
postgres=# show config_file ;
config_file
------------------------------
/data/pgdata/postgresql.conf
(1 row)
另外在从9.4版本开始,PostgreSQL引入了一个新的配置文件 postgresql.auto.conf ,主要用来存储PostgreSQL在运行过程中,利用alter system 修改了参数并持久化以后的配置。若postgresql.conf 和postgresql.auto.conf 存在相同配置的情况下系统优先执行 auto.conf 这个文件,换句话说 auto.conf 配置文件优先级高于 conf 文件。
示例演示:
postgres=# show work_mem ;
work_mem
----------
5242kB
(1 row)
postgres=# ALTER SYSTEM SET work_mem TO '2MB';
ALTER SYSTEM
[postgres@sp_65 pgdata ]$ pg_ctl reload
server signaled
[postgres@sp_65 pgdata ]$ psql -c 'show work_mem'
work_mem
----------
2MB
(1 row)
[postgres@sp_65 pgdata ]$ cat postgresql.auto.conf
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
work_mem = '2MB'
附录:
# PostgreSQL 所有配置生效方式
SELECT name,CASE context
WHEN 'postmaster'
THEN '* RESTART *'
WHEN 'sighup'
THEN '* Reload *'
WHEN 'backend'
THEN '* Reload *'
WHEN 'superuser-backend'
THEN '* Reload - Superuser Session *'
WHEN 'superuser'
THEN '* Reload - Superuser SET *'
WHEN 'user'
THEN '* Reload - User SET *'
WHEN 'internal'
THEN '* Initialized *'
END AS Service_Context
FROM pg_settings
ORDER BY Service_Context;
访问策略配置文件:主要影响当前数据库实例的连接行为(配置白名单访问策略)。比如允许某个网段的某个用户,以某种加密策略连接到某个数据库的验证方式。存放在数据库集群的数据目录里。
#查看访问策略配置文件的位置
postgres=# show hba_file;
hba_file
--------------------------
/data/pgdata/pg_hba.conf
(1 row)
# hba的意思是"host-based authentication", 也就是基于主机的认证。
该配置文件有5个参数,分别为:TYPE(主机类型)、DATABASE(数据库名)、USER(用户名)、ADDRESS(IP地址和掩码)、METHOD(加密方法)。
1.2 服务进程
postgres(postmaster):主进程,postgres进程是 PostgreSQL服务中所有进程的父进程,是整个数据的总控进程。通过pg_ctl启动 PostgreSQL服务的主进程postgres,当数据库启动后会从物理内存中分配shared memory区域,然后fork 出一些辅助子进程,必要时启动复制进程,并等待来自客户端的连接请求,每产生一个连接就会生成一个backend process。
当客户端调用接口向数据库发起连接请求时,首先是postgres 进程进行监听客户端连接、验证信息,如果通过会向下fork()出多个连接服务进程进行连接管理。而postgres 进程除了监听连接、验证功能之外,还会管理整个数据库实例的启动和停止、管理数据文件、当服务进程出错时进行修复、管理数据库运行相关的辅助进程等。
一个postgres进程监听一个网络端口,默认端口是5432。虽然同一台主机上可以运行多个 PostgreSQL服务(不同集簇),但是每个服务器之间应该设置监听不同的端口号。
Backend Processes:服务进程,主要处理一个连接的客户端发出的所有语句。它通过单个 TCP 连接与客户端通信,并在客户端断开连接时终止。由于一个连接只允许操作一个数据库,因此多实例时,在连接到 PostgreSQL 服务器时,必须明确指定要使用的数据库。当然,允许多个客户端同时使用操作同一个数据库,配置参数max_connections控制客户端的最大数量(默认为 100)。
如果WEB应用等很多客户端频繁重复连接和断开与PostgreSQL服务器的连接,会增加建立连接和创建后端进程的成本,因为PostgreSQL没有实现本地连接池功能,这种情况对数据库服务器的性能有负面影响。为了处理这种情况,通常使用池中间件(pgbouncer 或pgpool-II)。
Backend Processes相关参数:
max_connections 最大连接数,默认100
superuser_reserved_connections 超级用户连接数,默认3
tcp_keepalives_idle 规定在操作系统向客户端发送一个TCP keepalive消息后无网络活动的时间总量。默认值0,表示选择操作系统默认值
tcp_keepalives_interval 规定未被客户端确认收到的TCP keepalive消息应重新传输的时间长度。如果指定值时没有单位,则以秒为单位。默认值0,表示选择操作系统默认值
tcp_keepalives_count 指定服务器到客户端的连接被认为中断之前可以丢失的TCP keepalive消息的数量。默认值0,表示选择操作系统默认值。
backgroud writer:后台写进程,主要负责把共享内存(shared buffer pool)中的脏页周期性的写入到磁盘。由于向数据库中插入或更新数据时,是直接在内存中进行更新(还未落盘),我们就把这部分内存中的数据称为脏块。这样做主要是主要为了提高更新或者插入的效率。
但是这也就引入了一个问题,内存中的数据和磁盘中已经持久化的数据不一致,所以backgroud writer 进程就是按照一定的周期,将脏块的数据写入到磁盘。这个更新的频率可以通过postgresql.conf配置文件中checkpointer 相关参数进行配置,过高或者过低的频率都有问题,比如说过高的话,磁盘IO过于频繁,性能会降低;过低时,有可能造成内存不足,当有新的数据要写入或者要查询脏块中的数据时,就需要将数据先写入到内存中,必然会造成更新或者查询更慢。所以我们进行配置时要找到一个合适的频率。
backgroud writer相关参数:
bgwriter_delay 指定后台写入器活动轮次之间的延迟,默认值200ms
bgwriter_lru_maxpages 在每个轮次中,不超过这么多个缓冲区将被后台写入器写出,默认值100 个缓冲区
bgwriter_lru_multiplier 每一轮次要写的脏缓冲区的数目基于最近几个轮次中服务器进程需要的新缓冲区的数目,默认值2.0
bgwriter_flush_after 只要后台写入的数据超过这个数量,尝试强制 OS 把这些写发送到底层存储上
checkpointer:检查点进程,主要是辅助bgwriter进行内存中脏数据块的写入,缩短数据库实例恢复的时间。类似于虚拟机的快照。
实际上,当backgroud writer 进程向磁盘中写入脏块时,是通过checkpointer进程实际写入的。backgroud writer 在扫描出脏块后,会发起写入的request,而checkpointer进程会读取这些request,将脏块批量写入磁盘,并且会记录已经写入后的脏块,从而保证下次只会写入新的脏块。
checkpointer 相关参数:
checkpoint_timeout 自动地执行检查点时间,默认值 5 min
max_wal_size wal日志文件最大空间,软限制,默认值 1GB
min_wal_size wal日志文件最小空间,默认值 80MB
checkpoint_completion_target 为了避免大批页面写入对I/O系统产生的冲击,一个检查点中对脏缓冲区的写出操作被散布到一段时间上,期望能够在下一个检查点启动之前的大约一半时间内完成每个检查点,默认值 0.5
checkpoint_flush_after checkpoint_flush_after允许强制 OS 超过一个可配置的字节数后将检查点写入的页面刷入磁盘。默认值 256kB
wal write:预写日志进程,保证数据库在插入、修改数据之前必须先将对应的变更操作(wal 缓存)写入到wal 日志并进行持久化到磁盘,也就是先写日志持久化后插入、修改数据的过程。如果遵循这个过程,那么就不需要在每次事物提交的时候都把数据块刷回到磁盘,因为在出现崩溃的情况下,可以用日志来恢复数据库。使用WAL主要的好处就是显著地减少了写磁盘的次数,因为在日志提交的时候只需要把日志文件刷新到磁盘,而不是事务修改所涉及的所有数据文件。
wal write 相关参数:
wal_level wal_level决定多少信息写入到 WAL 中,默认值 replica,它会写入足够的数据以支持WAL归档和复制,包括在后备服务器上运行只读查询
fsync PostgreSQL服务器将尝试确保更新被物理地写入到磁盘,做法是发出fsync()系统调用。虽然关闭fsync常常可以得到性能上的收益,但当发生断电或系统崩溃时可能造成不可恢复的数据损坏
synchronous_commit 当数据库提交事务时是否需要等待WAL日志写入硬盘后才向客户端返回成功,默认值 on
# 单实例 --单实例下没有远程节点,所以只有三个值可以设(on、off、local),此时设为on和local基本是一个意思,就只有on、off两种值
1. synchronous_commit = on / local
单实例下设置成 on或local 均表示提交事务时需等待相应WAL缓存中数据写入本地WAL日志文件后才向客户端返回成功。设置成on非常安全,但数据库性能有损耗 。
2. synchronous_commit = off
单实例下设置成 off 表示提交事务时不需等待相应WAL数据写入本地WAL日志文件即可向客户端返回成功。
当数据库宕机时最新提交的少量事务可能丢失,但数据库重启后会认为这些事务异常中止。设置成off能够提升数据库性能,因此对于数据准确性没有精确要求同时追求数据库性能的场景建议设置成off。
# 多实例
1. synchronous_commit = on
当前同步的备库回复主库已经收到了事务的提交记录并将其刷入了磁盘,主服务器上的事务才会提交。
这保证事务将不会被丢失,除非主服务器和所有同步后备都遭受到了数据库存储损坏的问题。
2. synchronous_commit = remote_apply
设置为remote_apply时,提交将会等待,当前同步的备库回复主库已经收到了事务的提交记录并且备库已经应用了该事务,保证主备数据完全一致性。
3. synchronous_commit = remote_write
设置为remote_write时,提交将会等待,当前同步的备库回复主库已经收到了事务的提交记录并且已经把该记录写出到它们的操作系统,足以保证数据在后备服务器的PostgreSQL实例崩溃时得以保存,但不能保证后备服务器遭受操作系统级别崩溃时数据能被保持,因为数据不一定必要在后备机上达到稳定存储。
4. synchronous_commit = local
设置local时,提交等待本地刷写到磁盘而不是复制完成。在使用同步复制时这通常不是我们想要的效果,但是为了完整性,还是提供了这样一个选项。
wal_sync_method 强制wal日志更新到磁盘的方法,linux系统默认值 fdatasync
full_page_writes 是否开启全页写入,此参数是为了防止块折断(块损坏)的一种策略,默认值 on
wal_compression 当这个参数为on时,如果full_page_writes 为打开或者处于基础备份期间,PostgreSQL服务器 会压缩写入到 WAL 中的完整页面镜像,默认值 off
wal_log_hints 当这个参数为on时,PostgreSQL服务器一个检查点之后页面被第一次修改期间把该磁盘页面的整个内容都写入 WAL,即使对所谓的提示位做非关键修改也会这样做,默认值 off
wal_buffers 用于还未写入磁盘的 WAL 数据的共享内存量,默认值 -1
wal_writer_delay 指定 WAL 写入器刷写 WAL 的频繁程度,默认值 200 ms
logger(logging collector):日志进程,主要负责收集所有其他的进程的日志信息。PostgreSQL的默认日志是关闭的,可在postgres.conf文件中logging_collector、log_destination、log_directory、log_filename、log_rotation_age、log_rotation_size、log_statement 等相关参数进行设置,打开日志收集,主进程就会启动logger日志进程。
logger 相关参数:
logging_collector 设置日志收集开关,默认值 off
log_destination 支持多种方法来记录服务器消息,包括stderr、csvlog和syslog,默认值 stderr
log_directory 设置日志文件存放位置,默认值 log
log_filename 设置日志文件的文件名格式,默认值 postgresql-%Y-%m-%d_%H%M%S.log
log_truncate_on_rotation 设置同名日志文件写入方式:覆盖/追加 ,默认值 off(追加)
log_rotation_age 设置单个日志文件的最大生存周期,默认值 1440 min(1d)
log_rotation_size 设置单个日志文件的最大空间,默认值 10
log_min_duration_statemen 设置慢语句超过多长时间被记录,默认值 -1 (关闭)
log_statement 设置哪些SQL语句被记录,默认值 none
autovacuum launcher:自动清理进程,主要负责对已经打标删除状态的数据进行清理以及负责统计信息的收集(用于查询优化时的代价估算,保证执行计划更优)。在PostgreSQL数据库中delete操作只是对原记录进行打标为删除状态,update同样也是对原记录进行delete打标并插入一条新数据,被delete打标的记录并不马上做删除处理,这就是为了PostgreSQL数据库的共享锁和独占锁机制,只有在其它事务没有在读取这些旧数据时,它们才会被删除。通过 autovacuum 进程来对历史无效数据进行清理,为vacuum process周期性的调用autovacuum work processes,释放磁盘空间。
autovacuum launcher 相关参数:
autovacuum_vacuum_threshold 单表上触发VACUUM的被插入、被更新或被删除元组的最小数量,默认值 50 个元组
autovacuum_vacuum_scale_factor 指定一个表尺寸的分数,在决定是否触发VACUUM时将它加到autovacuum_vacuum_threshold上,默认值 0.2(表尺寸的20%)
vacuum_cost_page_hit 清理一个在共享缓存中找到的缓冲区的估计代价,默认值 1
vacuum_cost_page_miss 清理一个必须从磁盘上读取的缓冲区的代价,默认值为10
vacuum_cost_page_dirty 当清理修改一个之前干净的块时需要花费的估计代价,它表示再次把脏块刷出到磁盘所需要的额外I/O,默认值为20。
autovacuum_vacuum_cost_delay 设置每次自动完成清理后睡眠时间,默认值 2ms。
autovacuum_vacuum_cost_limit 设置完成一次清理的代价限制值,默认值 -1
archiver:归档进程,主要负责对wal日志进行备份归档。由于wal日志是循环覆盖的,所以就有了 archiver(9.3之前叫pgarch) 进程,可以保证wal日志在覆盖前进行备份归档,另外PostgreSQL从8.x版本开始支持PITR(Point-In-Time-Recovery)技术恢复也是利用该进程,对全备之后的位点日志进行归档,保证全备文件+wal日志恢复至任意时间点。需要注意的是PostgreSQL默认归档配置是是关闭的,要在postgresql.conf文件中设置archive_mode、archive_command相关参数。
archiver 相关参数:
archive_mode 设置归档开关。默认值off
archive_command 设置wal日志归档到某个位置。
archive_timeout 设置限制未归档数据存在的时间,默认 0s
stats collector :统计信息收集进程,主要负责收集表数据的统计信息以用于数据库优化器的代价估算。如在一个表和索引上进行了多少次插入、更新与删除操作、磁盘块的读写次数、行的读写次数、磁盘块的数量和元组的数量、每个表上最近一次执行清理和分析操作的时间,以及统计每个用户自定义函数调用执行时间等。系统表pg_statistic存储了stats 进程采集的各类统计信息。另外在数据库实例的目录下有与统计信息收集器相关的文件,pg_stat_tmp文件则是stat进程和各个后台进程,进行交互的临时文件所在地。
walsender/walreceiver:wal日志发送/接受进程,walsender进程是streaming replication环境中master节点发送wal日志的进程,在standby节点启动时,standby节点向master发送连接请求,master节点的postgres主进程接收到请求后,启动该进程与standby节点的walreceiver进程建立通讯连接,用于传输WAL Record。
walsender/walreceiver 相关参数:
max_wal_senders 设置来自备服务器或流式基础备份客户端的并发连接的最大数量(即同时运行 WAL 发送进程的最大数) 默认值 10
max_standby_archive_delay 设置当备机处于活动状态时,决定取消那些与即将应用的 WAL 项冲突的后备机查询之前,后备服务器应该等待多久,当 WAL 数据被从 WAL 归档(并且因此不是当前的 WAL)时,max_standby_archive_delay可以应用,默认值 30s
max_standby_streaming_delay 设置当备机处于活动状态时,决定取消那些与即将应用的 WAL 项冲突的后备机查询之前,后备服务器应该等待多久,当 WAL 数据正在通过流复制被接收时,max_standby_streaming_delay可以应用,默认值 30s
wal_receiver_status_interval 设置在备机上的 WAL 接收者进程向主服务器或上游后备机发送有关复制进度的信息的最小频度,默认值是 10s
hot_standby_feedback 设置指定备机是否将会向主服务器或上游后备机发送有关于后备机上当前正被执行的查询的反馈,默认值 0ff
hot_standby 设置在恢复期间,是否能够连接并运行查询,默认值是on
logical replication launcher: 逻辑复制进程,主要负责基于表级别的复制,是一种粒度可细的复制。使用发布端/订阅端模型和订阅复制槽技术,订阅端通过 logical replication launcher进程向发布端的订阅表获取更新信息,然后在订阅端回放WAL日志中的逻辑条目,保持复制表的数据同步,注意这里不是“SQL”复制,而是复制SQL操作的结果。
logical replication launcher 相关参数:
wal_sender_timeout 中断停止活动超过这个时间量的复制连接,默认值是 60s
wal_receiver_timeout 中止非活动状态超过这个时间量的复制链接,默认值 60s
max_replication_slots 设置发布端支持的复制槽最大数量,默认值为10
max_logical_replication_workers 设置订阅端逻辑复制工作者的最大数目,默认值 4
max_sync_workers_per_subscription 设置每个订阅的同步工作者的最大数目,默认值为2
声明
因小编个人水平有限,专栏中难免存在错漏之处,请勿直接复制文档中的参数、命令或方法应用于线上环境中操作。
更多精彩内容,欢迎关注微信公众号<