查看和终止 PostgreSQL 连接会话

作者: 不剪发的Tony老师
毕业于北京航空航天大学,十多年数据库管理与开发经验,目前在一家全球性的金融公司从事数据库架构设计。CSDN学院签约讲师以及GitChat专栏作者。csdn上的博客收藏于以下地址:https://tonydong.blog.csdn.net

文章目录

        利用视图 pg_stat_activity 查看连接会话
        通过操作系统命令查看连接会话
        利用 pg_cancel_backend() 终止正在运行的语句
        通过操作系统命令终止正在运行的语句
        利用 pg_terminate_backend() 终止连接会话
        通过操作系统命令终止连接会话

大家好,我是只谈技术不剪发的 Tony 老师。今天给大家介绍一下如何如何查看和终止 PostgreSQL 的连接会话。

在 PostgreSQL 中,配置参数 max_connections 决定了数据库的并发连接上限,默认值为 100:

postgres=> show max_connections;
 max_connections
-----------------
 100
(1 row)

这个数值还包括了预留给 superuser 的一些连接,具体数量由参数 superuser_reserved_connections 决定:

postgres=> show superuser_reserved_connections;
 superuser_reserved_connections
--------------------------------
 3
(1 row)

 

也就是说,当连接数到达 max_connections - superuser_reserved_connections 时,只有超级用户才能建立新的数据库连接;普通用户连接时将会返回错误信息“FATAL: sorry, too many clients already.”或者“FATAL: remaining connection slots are reserved for non-replication superuser connections”。当我们遇到这种连接数过多的错误,或者由于其他原因需要找出目前存在哪些客户端的连接时,可以采用以下方法。
利用视图 pg_stat_activity 查看连接会话

PostgreSQL 动态统计视图 pg_stat_activity 中的每一行代表了一个后台进程,包含了该进程当前活动相关的信息。

postgres=> select pid,
       datname as database_name,
       usename as user_name,
       application_name,
       client_addr,
       backend_start,
       state,
       state_change,
       wait_event_type,
       wait_event,
       query,
       backend_type
from pg_catalog.pg_stat_activity;
pid  |database_name|user_name|application_name                         |client_addr |backend_start      |state |state_change       |wait_event_type|wait_event         |query                                                                                                                                                                                                                                                          |backend_type                |
-----|-------------|---------|-----------------------------------------|------------|-------------------|------|-------------------|---------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------|
 1677|             |         |                                         |            |2020-07-06 09:29:33|      |                   |Activity       |AutoVacuumMain     |                                                                                                                                                                                                                                                               |autovacuum launcher         |
 1679|             |postgres |                                         |            |2020-07-06 09:29:33|      |                   |Activity       |LogicalLauncherMain|                                                                                                                                                                                                                                                               |logical replication launcher|
23483|hrdb         |postgres |DBeaver 7.1.2 - Main <hrdb>              |192.168.56.1|2020-07-08 08:09:58|idle  |2020-07-08 08:09:58|Client         |ClientRead         |SHOW search_path                                                                                                                                                                                                                                               |client backend              |
23484|hrdb         |postgres |DBeaver 7.1.2 - Metadata <hrdb>          |192.168.56.1|2020-07-08 08:09:58|idle  |2020-07-08 08:09:58|Client         |ClientRead         |SELECT t.oid,t.*,c.relkind,format_type(nullif(t.typbasetype, 0), t.typtypmod) as base_type_name¶FROM pg_catalog.pg_type t¶LEFT OUTER JOIN pg_class c ON c.oid=t.typrelid¶WHERE typnamespace=$1 ¶ORDER by t.oid                                                 |client backend              |
23486|pagila       |postgres |DBeaver 7.1.2 - SQLEditor <Script-13.sql>|192.168.56.1|2020-07-08 08:09:58|active|2020-07-08 08:10:30|               |                   |select pid,¶       datname as database_name,¶       usename as user_name,¶       application_name,¶       client_addr,¶       backend_start,¶       state,¶       state_change,¶       wait_event_type,¶       wait_event,¶       query,¶       backend_type¶fr|client backend              |
23487|pagila       |postgres |DBeaver 7.1.2 - Main <pagila>            |192.168.56.1|2020-07-08 08:09:58|idle  |2020-07-08 08:09:58|Client         |ClientRead         |SHOW search_path                                                                                                                                                                                                                                               |client backend              |
23488|pagila       |postgres |DBeaver 7.1.2 - Metadata <pagila>        |192.168.56.1|2020-07-08 08:09:58|idle  |2020-07-08 08:10:00|Client         |ClientRead         |SELECT t.oid,t.*,c.relkind,format_type(nullif(t.typbasetype, 0), t.typtypmod) as base_type_name FROM pg_catalog.pg_type t¶LEFT OUTER JOIN pg_class c ON c.oid=t.typrelid¶WHERE t.oid=$1                                                                        |client backend              |
 1675|             |         |                                         |            |2020-07-06 09:29:33|      |                   |Activity       |BgWriterHibernate  |                                                                                                                                                                                                                                                               |background writer           |
 1674|             |         |                                         |            |2020-07-06 09:29:33|      |                   |Activity       |CheckpointerMain   |                                                                                                                                                                                                                                                               |checkpointer                |
 1676|             |         |                                         |            |2020-07-06 09:29:33|      |                   |Activity       |WalWriterMain      |                                                                                                                                                                                                                                                               |walwriter                   |

查询结果不仅返回了客户端连接对应的服务器进程,也包括 PostgreSQL 服务器的各种守护进程。其中,

    pid 代表了后台进程的 id;
    datname 是进程连接的数据库,对于后台守护进程显示为空;
    usename 是连接数据库使用的用户名,对于后台守护进程显示为空;
    application_name 是连接数据库的应用程序,对于后台守护进程显示为空;
    client_addr 是客户端的 IP 地址,对于后台守护进程或者通过 Unix 套接字连接的进程显示为空;
    backend_start 是进程启动的时间点,对于客户端的后台进程是连接服务器的时间点;
    state 代表了进程当前的状态,可能的取值包括 active、idle、idle in transaction、idle in transaction (aborted)、fastpath function call 以及 disabled;
    state_change 是最后一次状态的修改时间;
    wait_event_type 表示进程正在等待的事件类型,如果没有等待显示为空;可能的取值包括 LWLock、Lock、BufferPin、Activity、Extension、Client、IPC、Timeout 以及 IO;
    wait_event 表示进程正在等待的事件名称,如果没有等待显示为空;
    query 是进程最后一次执行的查询语句。对于 active 状态,显示正在执行的查询;其他状态显示上一次执行的查询;
    backend_type 是进程的类型。

    📝等待事件 wait_event 和进程状态 state 是相互独立的。如果进程处于 active 状态,可能正在等待某个事件,也可能没有等待事件如果状态为 active 并且 wait_event 不为空,意味着正在执行的查询被其他进程阻塞。

视图 pg_stat_activity 中还包含了更多的字段,具体可以参考官方文档。
通过操作系统命令查看连接会话

对于 Linux 操作系统,我们也可以使用ps命令查看 PostgreSQL 后台进程:

ps -ef|grep 'postgres'|grep -v 'grep'
postgres  1258     1  0 Jul06 ?        00:00:09 /usr/pgsql-12/bin/postmaster -D /var/lib/pgsql/12/data/
postgres  1335  1258  0 Jul06 ?        00:00:00 postgres: logger   
postgres  1674  1258  0 Jul06 ?        00:00:00 postgres: checkpointer   
postgres  1675  1258  0 Jul06 ?        00:00:05 postgres: background writer   
postgres  1676  1258  0 Jul06 ?        00:00:05 postgres: walwriter   
postgres  1677  1258  0 Jul06 ?        00:00:05 postgres: autovacuum launcher   
postgres  1678  1258  0 Jul06 ?        00:00:11 postgres: stats collector   
postgres  1679  1258  0 Jul06 ?        00:00:00 postgres: logical replication launcher   
postgres 23483  1258  0 08:09 ?        00:00:00 postgres: postgres hrdb 192.168.56.1(63614) idle
postgres 23484  1258  0 08:09 ?        00:00:00 postgres: postgres hrdb 192.168.56.1(63615) idle
postgres 23486  1258  0 08:09 ?        00:00:00 postgres: postgres pagila 192.168.56.1(63616) idle
postgres 23487  1258  0 08:09 ?        00:00:00 postgres: postgres pagila 192.168.56.1(63617) idle
postgres 23488  1258  0 08:09 ?        00:00:00 postgres: postgres pagila 192.168.56.1(63618) idle

其中,1258 是 postmaster 主进程;其他进程都是它的子进程。这种方式显示的进程信息相对简单一些。
利用 pg_cancel_backend() 终止正在运行的语句

函数 pg_cancel_backend(pid) 可以用于取消进程正在执行的查询,其中 pid 就是进程 id,可以通过上面的 pg_stat_activity 视图进行查看。

我们新建一个数据库连接,并且执行以下语句:

-- 新建数据库连接
postgres=> select pg_sleep(60);

 

pg_sleep 函数可以将当前会话的进程暂停指定时间,这里是 60 秒。

然后在另一个会话中终止该进程正在执行的查询:

-- 另一个连接会话
postgres=> select pid,
       query
from pg_catalog.pg_stat_activity
where wait_event = 'PgSleep';
pid  |query               |
-----|--------------------|
28582|select pg_sleep(60);|

postgres=> select pg_cancel_backend(28582);
pg_cancel_backend|
-----------------|
true             |

   

函数 pg_cancel_backend() 执行成功后返回 true,此时第一个连接会话将会返回以下错误:

ERROR:  canceling statement due to user request

   

虽然当前查询被终止,但是连接会话仍然存在,可以继续执行其他查询。
通过操作系统命令终止正在运行的语句

pg_cancel_backend() 函数实际上是给进程发送了一个 SIGINT 信号。因此,对于 Linux 操作系统,我们也可以使用kill命令终止终止正在运行的语句:

kill -2 pid

 

其中,-2 代表了 SIGINT 信号;pid 是进程 id。
利用 pg_terminate_backend() 终止连接会话

有时候 pg_cancel_backend() 需要等待很长时间才能终止正在执行的查询,为此我们也可以使用 pg_terminate_backend(pid) 函数强制终止整个连接进程。

例如,我们可以使用以下语句终止连接进程(28582):

-- 另一个连接会话
postgres=> select pg_terminate_backend(28582);
pg_terminate_backend|
--------------------|
true                |

  

函数 pg_terminate_backend() 执行成功后返回 true,此时第一个连接会话执行任何操作都会返回以下错误:

postgres=> select 1;
FATAL:  terminating connection due to administrator command
server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.

   

从错误信息可以看出当前连接被异常关闭,同时 psql 自动进行了重新连接。
通过操作系统命令终止连接会话

函数 pg_terminate_backend() 实际上是给进程发送了一个 SIGTERM 信号。因此,对于 Linux 操作系统,我们也可以使用kill命令终止 PostgreSQL 后台进程:

kill -9 pid
kill -15 pid

其中,-9 代表的是 SIGKILL 信号;-15 代表的是 SIGTERM 信号。

除了使用命令查看和终止 PostgreSQL 连接会话之外,pgAdmin 管理工具也提供了相应的图形操作。在 Dashboard 面板最下面的 Server Activity 区域可以查看当前连接的会话、锁、预编译事务以及配置信息,同时可以终止正在执行的查询和连接进程。