一网打尽: PostgreSQL中kill -9使用禁忌及所有相关signal用法详解

文摘   科技   2024-08-03 06:02   德国  

前言

本来来自postgresweekly (2024.1.17那一期)推荐的技术文章。重新加工整理,并加入本人自己的一些附加实验。总之一句话:KILL -9 戾气太重,千万不要在PostgreSQL生产环境当中使用。后果非常严重。

以下是那篇文章的原文。kill -9 explained for PostgreSQL[1]

是否要终止数据库连接? 或者你想用kill -9? 在你的PostgreSQL数据库服务器上?在你这么做之前,有些事情你应该知道。因此,我们想在这篇博客中回答的问题是: 我如何正确地终止PostgreSQL进程?

1.杀死PostgreSQL进程

在我们讨论进程终止之前,首先看一下操作系统级别的简单PostgreSQL实例/集群是有意义的:

1200474 ?        Ss     0:00 /usr/pgsql-15/bin/postgres -D sample_db
1200475 ? Ss 0:00 _ postgres: logger
1200476 ? Ss 0:00 _ postgres: checkpointer
1200477 ? Ss 0:00 _ postgres: background writer
1200479 ? Ss 0:00 _ postgres: walwriter
1200480 ? Ss 0:00 _ postgres: autovacuum launcher
1200481 ? Ss 0:00 _ postgres: logical replication launcher

我们在这里看到的是postmaster进程和它的子进程,它们共同构成了PostgreSQL的核心系统基础设施。这个基础架构中的大多数进程都可以很好地终止,没有任何问题:

[sql gutter="false"]
[hs@sample ~]$ kill 1200480

我们刚刚毁掉的是autovacuum进程。这完全不是问题,因为postmaster父进程会立即启动一个新的子进程: 我们可以通过新的进程ID来判断,这个进程ID可以在进程表中看到。

1.1 PostgreSQL基本上会确保这个东西总是在运行:

1200474 ?        Ss     0:00 /usr/pgsql-15/bin/postgres -D sample_db
1200475 ? Ss 0:00 _ postgres: logger
1200476 ? Ss 0:00 _ postgres: checkpointer
1200477 ? Ss 0:00 _ postgres: background writer
1200479 ? Ss 0:00 _ postgres: walwriter
1200481 ? Ss 0:00 _ postgres: logical replication launcher
1200524 ? Ss 0:00 _ postgres: autovacuum launcher

为了更好地理解这一点,我们必须了解kill命令的作用。它实际上并不杀死任何东西,它向操作系统进程发送一个信号。名称“kill”仍然是合适的,因为目标进程没有显式处理的任何信号都将导致其立即终止

1.2 SIGTERM信号 与 kill -9的对比

请记住,我们在这里使用了**“正常”kill(它发送一个SIGTERM信号)。然而,并不是所有的kill都是一样的。“正常”的kill可以被应用程序捕获并处理。基本上发生的事情是,auto vacuum启动进程已经捕获了SIGTERM信号并正确地终止了自己**。“适当”意味着所有共享资源都保持一致、干净的状态,并且没有剩余资源可以通过系统在某个随机位置引起问题。然而,普通的kill并不是kill -9所做的。问题是:“-9”发送SIGKILL信号,目标进程无法捕获和处理;它只是被操作系统粗暴地销毁,可能使共享内存和其他资源处于不一致的状态。这是在终止进程时必须牢记的一个极其重要的区别。

2. 以"-9"的方式杀掉数据库连接

但是如果我们残忍地终止一个数据库连接会发生什么呢?最后一个进程是到PostgreSQL的标准连接。用户hs通过本地IPv6连接连接到postgres数据库。详情如下:

1200474 ?        Ss     0:00 /usr/pgsql-15/bin/postgres -D sample_db
1200475 ? Ss 0:00 _ postgres: logger
1200476 ? Ss 0:00 _ postgres: checkpointer
1200477 ? Ss 0:00 _ postgres: background writer
1200479 ? Ss 0:00 _ postgres: walwriter
1200481 ? Ss 0:00 _ postgres: logical replication launcher
1200524 ? Ss 0:00 _ postgres: autovacuum launcher
1200623 ? Ss 0:00 _ postgres: hs postgres ::1(40498) idle

2.1 杀掉一些进程

用户连接被粗暴地消除了,但是仔细看看发生了什么:

[hs@sample ~]$ kill -9 1200623
[hs@sample ~]$ ps axf | grep post
1200474 ? Ss 0:00 /usr/pgsql-15/bin/postgres -D sample_db
1200475 ? Ss 0:00 _ postgres: logger
1200628 ? Ss 0:00 _ postgres: checkpointer
1200629 ? Ss 0:00 _ postgres: background writer
1200630 ? Ss 0:00 _ postgres: walwriter
1200631 ? Ss 0:00 _ postgres: autovacuum launcher
1200632 ? Ss 0:00 _ postgres: logical replication launcher

2.2 大多数进程都消失了,并使用新的进程ID重新启动。为什么呢?

前面,我提到“-9”发送一个不可捕获的信号,这意味着进程不能对kill作出反应。因此,进程可能在任何时候终止,这反过来意味着我们不能依赖于它使数据库保持一致状态的事实。这个过程可能会让我们处于任何状态。操作可能在共享内存、磁盘或其他任何地方发生更改时被终止。这意味着我们不能再信任共享内存的内容了。共享缓冲区内的一些随机块可能会损坏,或者发生了其他可能导致潜在损坏的事情。

2.3 PostgreSQL在kill -9之后实际做了什么?

PostgreSQL处理这种情况的方法是立即删除所有连接,清空内存并从最近的检查点启动WAL恢复。基本上,PostgreSQL做的事情和“正常数据库崩溃”时做的事情是一样的。

其主要优点是您可能会丢失几个数据库连接,并且不会面临数据库损坏。但是,**如果在繁忙的系统上“kill -9”,可能会无意中消除数千个数据库连接,这可能会产生不可预见的后果。因此,首先运行kill -9通常不是一个好主意。如果你这样做,重要的是要了解幕后实际发生了什么,并了解其含义。

以上就是那篇文章的主体内容。其实,我们可以把kill以及signal(信号)发送,整个的知识整理一下。

3. PostgreSQL中用到的信号详解

朋友们,众所周知,PostgreSQL中用到了哪些信号呢?我们可以从停止一个PostgreSQL实例开始探索:

停止PostgreSQL的文档[2]可参考:https://www.postgresql.org/docs/15/app-pg-ctl.html

pg_ctl stop -m i[mmediate] | f[ast] | s[mart]

smart: “智能”模式不允许新连接,然后等待所有现有客户端断开连接。如果服务器处于热备状态,一旦所有客户端断开连接,恢复和流复制将被终止。
fast: “快速”模式(默认)不等待客户端断开连接。将回滚所有活动事务,并强制断开客户端连接,然后关闭服务器。这个是默认停止模式。
immediate: “立即”模式将立即中止所有服务器进程,而不需要彻底关机。这种选择将在下次服务器启动时导致崩溃恢复周期。

3.1 PostgreSQL常见的三个信号

但是实际上,它们是分别往主进程发送三个不同的信号。

1.`SIGTERM`(信号15):这是一个终止信号,通知进程正常关闭。
PostgreSQL 会在接收到此信号后尽快完成当前事务,然后安全地关闭服务器。
这是推荐的关闭 PostgreSQL 服务器的方法。
2.`SIGINT`(信号2):这是一个中断信号,通常用于停止正在运行的程序。
在 PostgreSQL 中,接收到此信号的服务器会尝试中断当前事务并快速关闭。
这可能会导致数据不一致,但在某些情况下(例如,需要紧急关闭服务器以解决问题)
可能是合适的。
3.`SIGQUIT`(信号3):这是一个退出信号,用于立即终止进程。
在 PostgreSQL 中,接收到此信号的服务器会立即关闭,
不等待当前事务完成。这可能导致数据损坏,仅在非常紧急的情况下使用。

具体对应起来:

pg_ctl stop -m smart 相当于 pg_ctl kill TERM {pid} 或者 kill SIGTERM {pid}
pg_ctl stop -m fast 相当于 pg_ctl kill QUIT {pid} 或者 kill SIGQUIT {pid}
pg_ctl stop -m immediate 相当于 pg_ctl kill INT {pid} 或者 kill SIGINT {pid}

而本文开初列出的“-9”只不过是SIGKILL的数值表示。Linux内核实现了约30个信号,每个信号由一个数字标识,介于1到31之间。

PostgreSQL使用了以下这些信号:

ABRT: SIGABRT导致程序异常终止
INT: 外部中断,通常由用户发起。在客户端,它是Control-C的结果,它通常会取消正在运行的程序
KILL: 发送的是SIGKILL信号. 使进程立即终止。KILL 信号不能被捕获或忽略
QUIT: 这是一个更有力的要求。它将不优雅地终止,仍然清理绝对需要清理的资源,但可能不会删除临时文件。当用户按下Ctrl+\时产生这个信号
TERM: SIGTERM信号是用于导致程序终止的通用信号,相当于KILL PID。这用于进程的优雅终止
HUP: 这是一个挂起请求,它用来告诉进程重新初始化自己
USR1: 用户定义信号1
USR2: 用户定义信号2

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

3.2 所有相关信号参考

以下列出所有相关的信号,以供参考:

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

详细参考:

PostgreSQL进程停止时发生了什么, archive进程会完成所有归档吗

PostgreSQL与信号量的爱恨纠葛

参考资料

[1]

kill -9 explained for PostgreSQL: https://www.cybertec-postgresql.com/en/kill-9-explained-postgresql/

[2]

停止PostgreSQL的文档: https://www.postgresql.org/docs/15/app-pg-ctl.html


我是【Sean】,  欢迎大家长按关注并加星公众号:数据库杂记。有好资源相送,同时为你提供及时更新。已关注的朋友,发送0、1到7,都有好资源相送。


往期导读: 
1. PostgreSQL中配置单双向SSL连接详解
2. 提升PSQL使用技巧:PostgreSQL中PSQL使用技巧汇集(1)
3. 提升PSQL使用技巧:PostgreSQL中PSQL使用技巧汇集(2)
4. PostgreSQL SQL的基础使用及技巧
5. PostgreSQL开发技术基础:过程与函数
6. PostgreSQL中vacuum 物理文件truncate发生的条件
7. PostgreSQL中表的年龄与Vacuum的实验探索:Vacuum有大用
8. PostgreSQL利用分区表来弥补AutoVacuum的不足
9. 也聊聊PostgreSQL中的空间膨胀与AutoVacuum
10. 正确理解SAP BTP中hyperscaler PG中的IOPS (AWS篇)

数据库杂记
PostgreSQL,SAP HANA,Sybase ASE/ASA,Oracle,MySQL,SQLite各类数据库, SAP BTP云计算技术, 以及陈式太极拳教学倾情分享。
 最新文章