ITPub博客

首页 > 数据库 > 数据库开发技术 > PostgreSQL与信号量的爱恨纠葛

PostgreSQL与信号量的爱恨纠葛

原创 数据库开发技术 作者:u_a9af4a561c3b 时间:2021-05-16 17:57:13 0 删除 编辑

操作系统上的kill信号

众所周知,PostgreSQL对数据库的操作与操作系统高度内联。现在,在我们深入研究案例的细节之前,我已经完成了操作系统的系统调用和PostgreSQL后台进程的kill信号,让我们了解里面有什么。

Linux基础

什么是进程?

进程是一段程序的执行实例。它在操作系统中执行特定的任务。每一个进程都会被分配一个唯一的数字,也称之为进程标识符(PID),这个整型数字介于2到32768之间。当启动一个进程时,分配的数字会从2开始,数字1通常是为init进程保留的。1号进程负责管理其他进程。

Process table

进程表负责描述当前所有已加载的进程。通过ps命令可以展示相关进程。默认情况下,ps只显示与终端、控制台、串行线或伪终端保持连接的进程。

为了查看所有的进程,可以使用-e或者 -f的选项获取完整信息,比如 ps -ef

postgres 28056 1 0 21:51 pts/0 00:00:01 /usr/local/pgsql/bin/postgres -D /u02/pgsql/data

在这个例子中,1是init进程,28056是子进程。

系统调用

系统调用有时又被称为内核调用,是在类unix操作系统中,活跃进程通过软中断对内核发出服务请求。

系统调用fork()

我们可以通过调用fork()来创建一个新的进程。这个系统调用会复制当前进程,并在进程表中插入一个新的记录,进程表中有许多其他一样的属性记录。只是,新创建的进程会是调用fork()的进程的子进程。新创建进程的PPID对应父进程的PID。

信号

信号即一个通知,由操作系统或某个应用发送给程序的消息。

一个信号可能由:

  1. 内核发给某个进程

  2. 一个进程发给另一个进程

  3. 某个进程发给自己

根据信号类型,信号会向特定进程发出某些事件的警告。

Linux内核实现了约30个信号,每个信号由一个数字标识,介于1到31之间。

比如,SIGKILL或者信号9,告诉程序某人正在尝试干掉它。现在,让我们将Linux的进程及信号与PostgreSQL关联起来。

PostgreSQL和Linux的关联

启动PostgreSQL时,第一个启动的进程时Postmaster。然后由Postmaster创建其他后台进程。如果你使用pstree命令来查看各个进程之间的关系,你会发现Postmaster进程是所有进程的父进程。Postmaster启动时,它需要知道数据的存储区域。具体位置需要通过 -D 选项或者PGDATA的环境变量来指定。

[postgres@asristgdb ~]$ ps -ef | grep postgres
postgres 7913 1 0 23:11 pts/3 00:00:00 /usr/local/pgsql/bin/postgres -D /u02/pgsql/data
postgres 7914 7913 0 23:11 ? 00:00:00 postgres: logger process
postgres 7916 7913 0 23:11 ? 00:00:00 postgres: checkpointer process
postgres 7917 7913 0 23:11 ? 00:00:00 postgres: writer process
postgres 7918 7913 0 23:11 ? 00:00:00 postgres: wal writer process
postgres 7919 7913 0 23:11 ? 00:00:00 postgres: autovacuum launcher process
postgres 7920 7913 0 23:11 ? 00:00:00 postgres: stats collector process

在这里,进程7913是Postmaster进程,它创建了多个被称之为后台工作进程的子进程。如你所见,这些后台工作进程的PPID是Postmaster进程的PID。Postmaster进程也负责创建后台进程,用于客户端连接。建议阅读一下:PostgreSQL的连接时如何建立的。

连接请求

[postgres@asristgdb ~]$ psql -d testdb -U testuser
psql (9.6.8)
Type "help" for help.

testdb=#

Process Output:
ps -ef | grep postgres (output truncated)
postgres 7994 7913 0 23:11 ? 00:00:00 postgres: testuser testdb [local] idle

我们可以通过pstree查看进程列表:

[postgres@asristgdb ~]$ pstree -p 7913
postgres(7913)¬postgres(7914)
postgres(7916)
postgres(7917)
postgres(7918)
postgres(7919)
postgres(7920)
[postgres@asristgdb ~]$

PostgreSQL和OS信号

PostgreSQL使用以下操作系统信号对数据库进程发起调用。

  1. ABRT

  2. INT

  3. QUIT

  4. TERM

  5. HUP

  6. USR1

  7. USR2

下面列表描述了每个信号的作用。

案例学习

我将上面表格中提到的所有信号发送给Postmaster以及其他后台进程,并捕获对应的结果。下表显示了当我向Postmaster进程发送KILL信号时系统的对应行为。

语法:pg_ctl kill SIGNALNAME PID

比如:/usr/local/pgsql/bin/pg_ctl kill INT 20958,20958是Postmaster进程的PID。

我还将相同的信号发给其他后台进程,结果如下:

为什么kill -9好比犯罪?

如上所述,kill -9不仅会终止单个进程,而且还会重新初始化其他所有进程。

任意一个进程被 kill -9终止后,Postmaster都会重置其他后台工作进程。

让我们看个例子,理解一下这个观点:

[postgres@postgreshelp ~]$ ps -ef | grep postgres
postgres 7913     1 0 Feb01 ?       00:00:01 /usr/local/pgsql/bin/postgres -D /u02/pgsql/data
postgres 7914 7913 0 Feb01 ?       00:00:00 postgres: logger process
postgres 7916 7913 0 Feb01 ?       00:00:00 postgres: checkpointer process
postgres 7917 7913 0 Feb01 ?       00:00:05 postgres: writer process
postgres 7918 7913 0 Feb01 ?       00:00:03 postgres: wal writer process
postgres 7919 7913 0 Feb01 ?       00:00:06 postgres: autovacuum launcher process
postgres 7920 7913 0 Feb01 ?       00:00:03 postgres: stats collector process
postgres 20568 7913 0 20:28 ?       00:00:00 postgres: testuser testdb [local] idle

这里,20568是某个空闲的客户端连接的PID,现在使用kill -9干掉该会话:

[postgres@asristgdb ~]$ kill -9 20568
[postgres@asristgdb ~]$

捕获的日志如下:

LOG:  server process (PID 20568) was terminated by signal 9: Killed
LOG: terminating any other active server processes
WARNING: terminating connection because of crash of another server process
DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT: In a moment you should be able to reconnect to the database and repeat your command.
LOG: all server processes terminated; reinitializing
LOG: database system was interrupted; last known up at 2019-02-01 23:11:41 IST
LOG: database system was not properly shut down; automatic recovery in progress
LOG: invalid record length at 41/E0D53F60: wanted 24, got 0
LOG: redo is not required
LOG: checkpoint starting: end-of-recovery immediate
LOG: checkpoint complete: wrote 0 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.026 s, sync=0.000 s, total=0.029 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB
LOG: MultiXact member wraparound protections are now enabled
LOG: database system is ready to accept connections
LOG: autovacuum launcher started

Postmaster进程也会重启所有的后台工作进程,我们可以使用ps 命令确认:

[postgres@asristgdb ~]$ ps -ef | grep postgres
postgres 20730 7913 0 20:30 ?       00:00:00 postgres: checkpointer process
postgres 20731 7913 0 20:30 ?       00:00:00 postgres: writer process
postgres 20732 7913 0 20:30 ?       00:00:00 postgres: wal writer process
postgres 20733 7913 0 20:30 ?       00:00:00 postgres: autovacuum launcher process
postgres 20734 7913 0 20:30 ?       00:00:00 postgres: stats collector process

每个进程分配了一个新的进程ID。

有时重置可能会导致损坏或错误。因此,强烈建议不要使用kill -9杀掉任何一个PostgreSQL进程,包括空闲进程。

作为替代,我们可以使用pg_cancen_backend(pid)或pg_terminate_backend(pid)指定进程PID,发送相应的信号(分别对应SIGINT和SIGTERM)。

经验

  1. Postmaster是每一个PostgreSQL进程的父进程

  2. 如果因为某个原因停止了,Postmaster会重启其他后台工作进程

  3. Postmaster针对每个客户请求创建一个新的进程

  4. 在你的环境里不要使用kill -9

小结

PostgreSQL目前还比较简陋没有类似Oracle的pmon进程,Oracle由于pmon进程的存在,在某个进程非正常退出后,会做好妥善的后事及清理工作。PostgreSQL由于没有,假如某个进程正在修改shared buffer里的某个数据块,然后被异常终止了,Postmaster为了安全,就会主动停下其他后台进程,做修复善后工作,改头换面再接受连接,所以老老实实用select pg_terminate_backend()和pg_cancen_backend()吧,要用也用kill(不带-9 )的那种。

另外对于我们常见的关闭PostgreSQL服务的方式中,-mi的方式,其实也用到了SIGKILL,假如5s还没有干掉你,那就只能sigkill了。

This is the Immediate Shutdown mode. The server will send SIGQUIT to all child processes and wait for them to terminate. If any do not terminate within 5 seconds, they will be sent SIGKILL. The master server process exits as soon as all child processes have exited, without doing normal database shutdown processing. This will lead to recovery (by replaying the WAL log) upon next start-up. This is recommended only in emergencies.

附所有信号:(来源:http://c.biancheng.net/view/3482.html)


原文作者:PostgreSQL学徒;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2020-07-14

  • 博文量
    306
  • 访问量
    139286