如何查找运行psql查询的脚本并匹配对应进程PID
Postgres后端进程PID与外部脚本PID的关联方法
两类PID分属不同的进程树,没有直接的父子继承关系,无法通过普通的ps命令遍历父子进程匹配,可通过以下无侵入或轻侵入的方案实现精准关联:
无侵入实现(无需修改现有脚本代码)
- 利用
pg_stat_activity内置的客户端连接锚点信息做TCP连接匹配
该视图本身已存储每个会话对应的客户端连接元数据:包括client_addr(发起连接的客户端IP)、client_port(客户端侧与Postgres通信的临时源端口),这组信息与外部脚本在系统上打开的TCP连接是一一对应的,不存在歧义。
操作步骤:- 从
pg_stat_activity中提取目标活跃查询对应的三个值:后端进程pid、client_addr、client_port - 在发起查询的客户端所在机器上,通过
ss -tunp或netstat -tunp命令,匹配对应client_addr和client_port的TCP连接输出行,该行会直接显示持有该连接的外部进程PID - 通过
ps -p <外部进程PID> -o args=即可获取对应脚本的完整路径、运行参数
注意:如果查到
client_port = -1,说明该会话走的是本地Unix套接字连接,不存在TCP端口标识,无法通过上述方法匹配,需要采用带标识的方案。 - 从
- 利用内核文件系统反向匹配连接对
对Linux系统,Postgres后端进程持有与客户端通信的socket文件描述符,可直接通过/proc目录下的进程信息反向定位对端进程:- 找到目标后端进程(即pg_stat_activity查到的pid)打开的socket文件:
sudo ls -l /proc/<postgres后端PID>/fd | grep socket,记录对应socket的inode号 - 遍历所有系统进程的fd目录,匹配持有相同inode号的socket,对应的进程就是发起连接的外部脚本进程
- 找到目标后端进程(即pg_stat_activity查到的pid)打开的socket文件:
轻侵入实现(适配Unix套接字/连接池场景)
- 在连接建立时通过
application_name参数传递自定义关联标识
这是可靠性最高的匹配方案,不受连接类型、连接池架构的限制。在外部脚本发起数据库连接时,将当前脚本的进程ID、脚本绝对路径作为application_name参数的值拼接传入,后续直接从pg_stat_activity的application_name字段读取对应元数据,无需跨进程查询系统信息。
示例(Shell调用psql的场景):
示例(Python脚本调用psycopg2的场景):psql "dbname=test user=postgres application_name=ext_pid_$$_script_$(realpath $0)" -c "SELECT 1;"import os, psycopg2 conn = psycopg2.connect( dbname="test", user="postgres", host="/var/run/postgresql", application_name=f"ext_pid_{os.getpid()}_script_{os.path.abspath(__file__)}" )
常见匹配误区
- 不要试图通过进程树的父子关系匹配:Postgres的后端进程是由数据库主进程fork生成的,和外部发起查询的脚本不在同一进程树链路上,顺着父PID遍历的方式完全无法找到对应关系
- 连接池场景下需动态更新标识:如果业务通过PgBouncer等连接池中转查询,直接通过TCP端口匹配找到的是连接池进程的PID,需要在每次获取连接时动态更新
application_name字段的业务标识,才能穿透连接池定位到真正的业务脚本来源
内容的提问来源于stack exchange,提问作者Alice Dorn
相关产品推荐
相关产品推荐

