暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL与信号量的爱恨纠葛

文章转载自公众号: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。

信号

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

一个信号可能由:

  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 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使用以下操作系统信号对数据库进程发起调用。

  1. ABRT

  2. INT

  3. QUIT

  4. TERM

  5. HUP

  6. USR1

  7. USR2

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

SIGNALUSAGE
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

TERMThe SIGTERM signal is a generic signal used to cause program termination, equivalent to KILL PID.This is used for graceful termination of a process
QUITIt 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+\
ABRTSIGABRT causes abnormal program termination
HUPIt is a hang up request, it is used to tell the process to reinitialize itself
USR1User defined signal 1
USR2User defined signal 2

案例学习

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

语法:pg_ctl kill SIGNALNAME PID

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

SIGNALPOSTMASTER PROCESSLOG
INTFast 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

TERMSmart 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

QUITImmediate ShutdownLOG: 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
ABRTForced termination by signal 6No 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
HUPReload configuration fileLOG: received SIGHUP, reloading configuration files
USR1NANA
USR2NANA

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

SignalWriter processWal writer processAutovacuum launcher processCheckpointer Processstats collector Process
INTDetraction of the running transactionDetraction of the running transaction, process restartDetraction of the running transactionRequest of the checkpoint execution
TERMNormal exit and restartNormal exit and restartNormal exit and restart
QUITforce termination of all processesforce termination of all processesforce termination of all processesforce termination of all processes
ABRTForced termination by signal 6Forced termination by signal 6Forced termination by signal 6Forced termination by signal 6
HUPReload configuration fileReload configuration fileReload configuration fileReload configuration fileReload configuration file
USR1NANANANA
USR2NANANANA

为什么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)。

经验

  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)


信 号默认行为描 述信号值
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



规模空前,再创历史 | 2020 PG亚洲大会圆满结束
PG ACE计划的正式发布
三期PostgreSQL国际线上沙龙活动的举办
六期PostgreSQL国内线上沙龙活动的举办

中国PostgreSQL分会与腾讯云战略合作协议签订


PostgreSQL 13.0 正式版发布通告

深度报告:开源协议那些事儿

从“非主流”到“潮流”,开源早已值得拥有

Oracle中国正在进行新一轮裁员,传 N+6 补偿

PostgreSQL与MySQL版权比较

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

四年三冠,PostgreSQL再度荣获“年度数据库”


更多新闻资讯行业动态技术热点,请关注中国PostgreSQL分会官方网站

https://www.postgresqlchina.com

中国PostgreSQL分会生态产品

https://www.pgfans.cn

中国PostgreSQL分会资源下载站

https://www.postgreshub.cn


点击此处阅读原文

↓↓↓

文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论