
文章转载自公众号:PostgreSQL学徒
作者:熊灿灿
操作系统上的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。
信号
信号即一个通知,由操作系统或某个应用发送给程序的消息。
一个信号可能由:
内核发给某个进程
一个进程发给另一个进程
某个进程发给自己
根据信号类型,信号会向特定进程发出某些事件的警告。
Linux内核实现了约30个信号,每个信号由一个数字标识,介于1到31之间。
比如,SIGKILL或者信号9,告诉程序某人正在尝试干掉它。现在,让我们将Linux的进程及信号与PostgreSQL关联起来。
PostgreSQL和Linux的关联
启动PostgreSQL时,第一个启动的进程时Postmaster。然后由Postmaster创建其他后台进程。如果你使用pstree命令来查看各个进程之间的关系,你会发现Postmaster进程是所有进程的父进程。Postmaster启动时,它需要知道数据的存储区域。具体位置需要通过 -D 选项或者PGDATA的环境变量来指定。
[postgres@asristgdb ~]$ ps -ef | grep postgrespostgres 7913 1 0 23:11 pts/3 00:00:00 /usr/local/pgsql/bin/postgres -D /u02/pgsql/datapostgres 7914 7913 0 23:11 ? 00:00:00 postgres: logger processpostgres 7916 7913 0 23:11 ? 00:00:00 postgres: checkpointer processpostgres 7917 7913 0 23:11 ? 00:00:00 postgres: writer processpostgres 7918 7913 0 23:11 ? 00:00:00 postgres: wal writer processpostgres 7919 7913 0 23:11 ? 00:00:00 postgres: autovacuum launcher processpostgres 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 testuserpsql (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 7913postgres(7913)¬postgres(7914)postgres(7916)postgres(7917)postgres(7918)postgres(7919)postgres(7920)[postgres@asristgdb ~]$
PostgreSQL和OS信号
PostgreSQL使用以下操作系统信号对数据库进程发起调用。
ABRT
INT
QUIT
TERM
HUP
USR1
USR2
下面列表描述了每个信号的作用。
| SIGNAL | USAGE |
|---|---|
| INT | external interrupt, usually initiated by the user., at client side it is the results of a Control-C which normally cancels a running program |
| TERM | The SIGTERM signal is a generic signal used to cause program termination, equivalent to KILL PID.This is used for graceful termination of a process |
| QUIT | It is a more forceful request. It shall terminate ungraceful, still cleaning up resources that absolutely need cleanup, but may not delete temporary files.This signal is generated when a user presses Ctrl+\ |
| ABRT | SIGABRT causes abnormal program termination |
| HUP | It is a hang up request, it is used to tell the process to reinitialize itself |
| USR1 | User defined signal 1 |
| USR2 | User defined signal 2 |
案例学习
我将上面表格中提到的所有信号发送给Postmaster以及其他后台进程,并捕获对应的结果。下表显示了当我向Postmaster进程发送KILL信号时系统的对应行为。
语法:pg_ctl kill SIGNALNAME PID
比如:/usr/local/pgsql/bin/pg_ctl kill INT 20958,20958是Postmaster进程的PID。
| SIGNAL | POSTMASTER PROCESS | LOG |
|---|---|---|
| INT | Fast Shutdown | LOG: received fast shutdown request LOG: aborting any active transactions LOG: autovacuum launcher shutting down LOG: shutting down LOG: checkpoint starting: shutdown 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.044 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB LOG: database system is shut down |
| TERM | Smart Shutdown | LOG: received smart shutdown request LOG: autovacuum launcher shutting down LOG: shutting down LOG: checkpoint starting: shutdown immediate LOG: checkpoint complete: wrote 0 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.028 s, sync=0.000 s, total=0.048 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB LOG: database system is shut down |
| QUIT | Immediate Shutdown | LOG: received immediate shutdown request 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: database system is shut down |
| ABRT | Forced termination by signal 6 | No Log during shutdown Log while startup: database system was interrupted; last known up at 2019-01-31 20:46:15 IST database system was not properly shut down; automatic recovery in progress invalid record length at 41/53969448: wanted 24, got 0 redo is not required checkpoint starting: end-of-recovery immediate checkpoint complete: wrote 0 buffers (0.0%); 0 transaction log file(s) added, 0 removed, 0 recycled; write=0.027 s, sync=0.000 s, total=0.030 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB MultiXact member wraparound protections are now enabled database system is ready to accept connections autovacuum launcher started |
| HUP | Reload configuration file | LOG: received SIGHUP, reloading configuration files |
| USR1 | NA | NA |
| USR2 | NA | NA |
我还将相同的信号发给其他后台进程,结果如下:
| Signal | Writer process | Wal writer process | Autovacuum launcher process | Checkpointer Process | stats collector Process |
|---|---|---|---|---|---|
| INT | Detraction of the running transaction | Detraction of the running transaction, process restart | Detraction of the running transaction | Request of the checkpoint execution | |
| TERM | Normal exit and restart | Normal exit and restart | Normal exit and restart | ||
| QUIT | force termination of all processes | force termination of all processes | force termination of all processes | force termination of all processes | |
| ABRT | Forced termination by signal 6 | Forced termination by signal 6 | Forced termination by signal 6 | Forced termination by signal 6 | |
| HUP | Reload configuration file | Reload configuration file | Reload configuration file | Reload configuration file | Reload configuration file |
| USR1 | NA | NA | NA | NA | |
| USR2 | NA | NA | NA | NA |
为什么kill-9好比犯罪?
如上所述,kill -9不仅会终止单个进程,而且还会重新初始化其他所有进程。
任意一个进程被 kill -9终止后,Postmaster都会重置其他后台工作进程。
让我们看个例子,理解一下这个观点:
[postgres@postgreshelp ~]$ ps -ef | grep postgrespostgres 7913 1 0 Feb01 ? 00:00:01 /usr/local/pgsql/bin/postgres -D /u02/pgsql/datapostgres 7914 7913 0 Feb01 ? 00:00:00 postgres: logger processpostgres 7916 7913 0 Feb01 ? 00:00:00 postgres: checkpointer processpostgres 7917 7913 0 Feb01 ? 00:00:05 postgres: writer processpostgres 7918 7913 0 Feb01 ? 00:00:03 postgres: wal writer processpostgres 7919 7913 0 Feb01 ? 00:00:06 postgres: autovacuum launcher processpostgres 7920 7913 0 Feb01 ? 00:00:03 postgres: stats collector processpostgres 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: KilledLOG: terminating any other active server processesWARNING: terminating connection because of crash of another server processDETAIL: 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; reinitializingLOG: database system was interrupted; last known up at 2019-02-01 23:11:41 ISTLOG: database system was not properly shut down; automatic recovery in progressLOG: invalid record length at 41/E0D53F60: wanted 24, got 0LOG: redo is not requiredLOG: checkpoint starting: end-of-recovery immediateLOG: 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 kBLOG: MultiXact member wraparound protections are now enabledLOG: database system is ready to accept connectionsLOG: autovacuum launcher started
Postmaster进程也会重启所有的后台工作进程,我们可以使用ps命令确认:
[postgres@asristgdb ~]$ ps -ef | grep postgrespostgres 20730 7913 0 20:30 ? 00:00:00 postgres: checkpointer processpostgres 20731 7913 0 20:30 ? 00:00:00 postgres: writer processpostgres 20732 7913 0 20:30 ? 00:00:00 postgres: wal writer processpostgres 20733 7913 0 20:30 ? 00:00:00 postgres: autovacuum launcher processpostgres 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)。
经验
Postmaster是每一个PostgreSQL进程的父进程
如果因为某个原因停止了,Postmaster会重启其他后台工作进程
Postmaster针对每个客户请求创建一个新的进程
在你的环境里不要使用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)
| 信 号 | 默认行为 | 描 述 | 信号值 |
|---|---|---|---|
| SIGABRT | 生成 core 文件然后终止进程 | 这个信号告诉进程终止操作。ABRT 通常由进程本身发送,即当进程调用 abort() 函数发出一个非正常终止信号时 | 6 |
| SIGALRM | 终止 | 警告时钟 | 14 |
| SIGBUS | 生成 core 文件然后终止进程 | 当进程引起一个总线错误时,BUS 信号将被发送到进程。例如,访问了一部分未定义的内存对象 | 10 |
| SIGCHLD | 忽略 | 当了进程结束、被中断或是在被中断之后重新恢复时,CHLD 信号会被发送到进程 | 20 |
| SIGCONT | 继续进程 | CONT 信号指不操作系统重新开始先前被 STOP 或 TSTP 暂停的进程 | 19 |
| SIGFPE | 生成 core 文件然后终止进程 | 当一个进程执行一个错误的算术运算时,FPE 信号会被发送到进程 | 8 |
| SIGHUP | 终止 | 当进程的控制终端关闭时,HUP 信号会被发送到进程 | 1 |
| SIGILL | 生成 core 文件然后终止进程 | 当一个进程尝试执行一个非法指令时,ILL 信号会被发送到进程 | 4 |
| SIGINT | 终止 | 当用户想要中断进程时,INT 信号被进程的控制终端发送到进程 | 2 |
| SIGKILL | 终止 | 发送到进程的 KILL 信号会使进程立即终止。KILL 信号不能被捕获或忽略 | 9 |
| SIGPIPE | 终止 | 当一个进程尝试向一个没有连接到其他目标的管道写入时,PIPE 信号会被发送到进程 | 13 |
| SIGQUIT | 终止 | 当用户要求进程执行 core dump 时,QUIT 信号由进程的控制终端发送到进程 | 3 |
| SIGSEGV | 生成 core 文件然后终止进程 | 当进程生成了一个无效的内存引用时,SEGV 信号会被发送到进程 | 11 |
| SIGSTOP | 停止进程 | STOP 信号指示操作系统停止进程的执行 | 17 |
| SIGTERM | 终止 | 发送到进程的 TERM 信号用于要求进程终止 | 15 |
| SIGTSTP | 停止进程 | TSTP 信号由进程的控制终端发送到进程来要求它立即终止 | 18 |
| SIGTTIN | 停止进程 | 后台进程尝试读取时,TTIN 信号会被发送到进程 | 21 |
| SIGTTOU | 停止进程 | 后台进程尝试输出时,TTOU 信号会被发送到进程 | 22 |
| SIGUSR1 | 终止 | 发送到进程的 USR1 信号用于指示用户定义的条件 | 30 |
| SIGUSR2 | 终止 | 同上 | 31 |
| SIGPOLL | 终止 | 当一个异步输入/输出时间事件发生时,POLL 信号会被发送到进程 | 23 |
| SIGPROF | 终止 | 当仿形计时器过期时,PROF 信号会被发送到进程 | 27 |
| SIGSYS | 生成 core 文件然后终止进程 | 发生有错的系统调用时,SYS 信号会被发送到进程 | 12 |
| SIGTRAP | 生成 core 文件然后终止进程 | 追踪捕获/断点捕获时,会产生 TRAP 信号。 | 5 |
| SIGURG | 忽略 | 当侖一个 socket 有紧急的或是带外数据可被读取时,URG 信号会被发送到进程 | 16 |
| SIGVTALRM | 终止 | 当进程使用的虚拟计时器过期时,VTALRM 信号会被发送到进程 | 26 |
| SIGXCPU | 终止 | 当进程使用的 CPU 时间超出限制时,XCPU 信号会被发送到进程 | 24 |
| SIGXFSZ | 生成 core 文件然后终止进程 | 当文件大小超过限制时,会产生 XFSZ 信号 | 25 |





新闻|Babelfish使PostgreSQL直接兼容SQL Server应用程序

更多新闻资讯,行业动态,技术热点,请关注中国PostgreSQL分会官方网站
https://www.postgresqlchina.com
中国PostgreSQL分会生态产品
https://www.pgfans.cn
中国PostgreSQL分会资源下载站
https://www.postgreshub.cn


点击此处阅读原文
↓↓↓




