Skip to content

PostgreSQL 进程监控:使用标准 Unix 工具 ​

概述 ​

PostgreSQL 数据库服务器在运行时会创建多个进程来处理不同的任务。通过标准的 Unix 工具(主要是 ps 命令),我们可以有效地监控这些进程的状态,了解数据库的运行情况。这对于数据库管理员进行故障排查、性能优化和系统监控至关重要。

PostgreSQL 进程架构 ​

使用 ps 命令监控 PostgreSQL 进程 ​

基本命令格式 ​

bash
# 查看所有 PostgreSQL 相关进程
ps auxww | grep ^postgres

# 或者使用更精确的过滤
ps -ef | grep postgres | grep -v grep

为什么使用 auxww 参数?

  • a:显示所有用户的进程
  • u:以用户友好的格式显示
  • x:显示没有控制终端的进程
  • ww:不限制输出宽度,显示完整的命令行 :::

完整示例分析 ​

让我们看一个实际的输出示例:

bash
$ ps auxww | grep ^postgres
postgres  15551  0.0  0.1  57536  7132 pts/0    S    18:02   0:00 postgres -i
postgres  15554  0.0  0.0  57536  1184 ?        Ss   18:02   0:00 postgres: background writer
postgres  15555  0.0  0.0  57536   916 ?        Ss   18:02   0:00 postgres: checkpointer
postgres  15556  0.0  0.0  57536   916 ?        Ss   18:02   0:00 postgres: walwriter
postgres  15557  0.0  0.0  58504  2244 ?        Ss   18:02   0:00 postgres: autovacuum launcher
postgres  15582  0.0  0.0  58772  3080 ?        Ss   18:04   0:00 postgres: joe runbug 127.0.0.1 idle
postgres  15606  0.0  0.0  58772  3052 ?        Ss   18:07   0:00 postgres: tgl regression [local] SELECT waiting
postgres  15610  0.0  0.0  58772  3056 ?        Ss   18:07   0:00 postgres: tgl regression [local] idle in transaction

进程类型详细分析 ​

进程类型PID描述作用
主进程15551postgres -i负责启动和管理所有其他进程
后台写入器15554background writer定期将脏页写入磁盘,减少检查点压力
检查点进程15555checkpointer执行检查点操作,确保数据持久性
WAL 写入器15556walwriter将预写日志(WAL)缓冲区写入磁盘
自动清理15557autovacuum launcher启动自动清理作业,维护表统计信息
客户端连接15582joe runbug 127.0.0.1 idle处理用户 joe 的连接,当前空闲
客户端连接15606tgl regression [local] SELECT waiting执行 SELECT,等待锁
客户端连接15610tgl regression [local] idle in transaction事务中空闲状态

客户端连接进程格式解析 ​

命令行格式 ​

PostgreSQL 为每个客户端连接进程使用以下格式:

postgres: user database host activity

格式组件说明 ​

活动状态指示器 ​

状态含义示例场景
idle空闲,等待客户端命令连接建立后,等待 SQL 语句
idle in transaction事务中空闲执行 BEGIN 后,等待下一条 SQL
SELECT正在执行 SELECT 查询复杂查询正在处理中
INSERT正在执行 INSERT 操作数据插入操作进行中
UPDATE正在执行 UPDATE 操作数据更新操作进行中
DELETE正在执行 DELETE 操作数据删除操作进行中
waiting等待锁释放被其他事务阻塞

实际业务场景示例 ​

场景 1:正常的应用连接 ​

bash
# 应用服务器连接
postgres: webapp myapp 192.168.1.100 idle

解释:

  • 用户:webapp(应用程序用户)
  • 数据库:myapp(应用数据库)
  • 主机:192.168.1.100(应用服务器 IP)
  • 状态:idle(等待下一个查询)

场景 2:报表查询 ​

bash
# 长时间运行的报表查询
postgres: analyst reporting 192.168.1.50 SELECT

解释:

  • 用户:analyst(分析师用户)
  • 数据库:reporting(报表数据库)
  • 主机:192.168.1.50(分析师工作站)
  • 状态:SELECT(正在执行复杂查询)

场景 3:锁等待问题 ​

bash
# 两个相互竞争的事务
postgres: user1 mydb 127.0.0.1 UPDATE waiting
postgres: user2 mydb 127.0.0.1 idle in transaction

问题分析:

  • user1 正在执行 UPDATE 操作,但被阻塞(waiting)
  • user2 在事务中处于空闲状态,可能持有锁
  • 需要检查锁依赖关系

集群名称显示 ​

配置集群名称 ​

sql
-- 查看当前集群名称
SHOW cluster_name;

-- 设置集群名称(需要重启)
ALTER SYSTEM SET cluster_name = 'production_db';
SELECT pg_reload_conf();

带集群名称的进程显示 ​

bash
$ psql -c 'SHOW cluster_name'
 cluster_name
--------------
 server1
(1 row)

$ ps aux | grep server1
postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: server1: background writer
postgres   27094  0.0  0.0  30096  1024 ?        Ss   11:34   0:00 postgres: server1: checkpointer
postgres   27095  0.0  0.0  30096  1024 ?        Ss   11:34   0:00 postgres: server1: walwriter

集群名称的作用 在多数据库集群环境中,集群名称帮助管理员快速识别进程属于哪个 PostgreSQL 实例,特别是在同一台服务器运行多个 PostgreSQL 实例时非常有用。 :::

锁等待检测与分析 ​

识别锁等待 ​

当看到进程状态为 waiting 时,表示该进程正在等待锁:

bash
postgres: tgl regression [local] SELECT waiting

查找锁阻塞关系 ​

sql
-- 查看当前锁状态
SELECT
    blocked_locks.pid AS blocked_pid,
    blocked_activity.usename AS blocked_user,
    blocking_locks.pid AS blocking_pid,
    blocking_activity.usename AS blocking_user,
    blocked_activity.query AS blocked_statement,
    blocking_activity.query AS current_statement_in_blocking_process
FROM pg_catalog.pg_locks blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity
        ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks blocking_locks
        ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity
        ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

锁等待处理流程 ​

进程标题更新配置 ​

update_process_title 参数 ​

sql
-- 查看当前设置
SHOW update_process_title;

-- 关闭进程标题更新(可以提高性能)
ALTER SYSTEM SET update_process_title = off;
SELECT pg_reload_conf();

性能考虑 ​

平台开启 update_process_title关闭 update_process_title
Linux轻微性能影响无影响,但失去实时状态
Solaris明显性能影响显著性能提升
BSD 系统中等性能影响性能提升

关闭进程标题更新的影响

  • 优点:减少系统调用开销,可能提升性能
  • 缺点:失去实时的活动状态指示,难以监控当前执行的操作 :::

平台特殊注意事项 ​

Solaris 系统 ​

在 Solaris 系统上使用 ps 命令需要特殊处理:

bash
# 错误的用法(不要使用)
/bin/ps -ef | grep postgres

# 正确的用法
/usr/ucb/ps auxww | grep postgres

Solaris 注意事项

  1. 必须使用 /usr/ucb/ps 而不是 /bin/ps
  2. 必须使用两个 w 标志(ww)
  3. 启动 postgres 命令时的显示必须比每个服务器进程的 ps 状态显示更短
  4. 如果不满足以上三个条件,ps 输出将显示原始的 postgres 命令行而不是有用的状态信息 :::

监控脚本示例 ​

基础监控脚本 ​

bash
#!/bin/bash
# postgresql_monitor.sh - PostgreSQL 进程监控脚本

echo "=== PostgreSQL 进程监控报告 ===="
echo "时间: $(date)"
echo

echo "=== 主要进程状态 ==="
ps auxww | grep "postgres:" | grep -v grep | while read line; do
    # 提取进程信息
    pid=$(echo $line | awk '{print $2}')
    cpu=$(echo $line | awk '{print $3}')
    mem=$(echo $line | awk '{print $4}')
    process_info=$(echo $line | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}')

    echo "PID: $pid | CPU: $cpu% | MEM: $mem% | $process_info"
done

echo
echo "=== 活跃连接统计 ==="
ps auxww | grep "postgres:" | grep -v "background\|checkpointer\|walwriter\|autovacuum" | grep -v grep | wc -l | awk '{print "活跃连接数: " $1}'

echo
echo "=== 等待锁的进程 ==="
ps auxww | grep "postgres:" | grep "waiting" | grep -v grep | while read line; do
    pid=$(echo $line | awk '{print $2}')
    process_info=$(echo $line | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}')
    echo "⚠️  PID: $pid - $process_info"
done

echo
echo "=== 长时间运行的事务 ==="
ps auxww | grep "postgres:" | grep "idle in transaction" | grep -v grep | while read line; do
    pid=$(echo $line | awk '{print $2}')
    start_time=$(echo $line | awk '{print $9}')
    process_info=$(echo $line | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}')
    echo "⏰ PID: $pid | 开始时间: $start_time - $process_info"
done

高级监控脚本 ​

bash
#!/bin/bash
# advanced_pg_monitor.sh - 高级 PostgreSQL 监控

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 阈值设置
MAX_CONNECTIONS=100
HIGH_CPU_THRESHOLD=80
HIGH_MEM_THRESHOLD=80

echo -e "${BLUE}=== PostgreSQL 高级监控报告 ===${NC}"
echo "时间: $(date)"
echo

# 检查服务状态
if pgrep postgres > /dev/null; then
    echo -e "${GREEN}✅ PostgreSQL 服务运行中${NC}"
else
    echo -e "${RED}❌ PostgreSQL 服务未运行${NC}"
    exit 1
fi

# 主进程信息
echo -e "\n${BLUE}=== 主进程信息 ===${NC}"
main_process=$(ps auxww | grep "postgres.*-" | grep -v grep | head -1)
if [ -n "$main_process" ]; then
    echo "$main_process"
else
    echo -e "${RED}未找到主进程${NC}"
fi

# 后台进程统计
echo -e "\n${BLUE}=== 后台进程统计 ===${NC}"
background_processes=("background writer" "checkpointer" "walwriter" "autovacuum launcher")
for process in "${background_processes[@]}"; do
    count=$(ps auxww | grep "postgres:" | grep "$process" | grep -v grep | wc -l)
    if [ $count -gt 0 ]; then
        echo -e "${GREEN}✅ $process: $count${NC}"
    else
        echo -e "${YELLOW}⚠️  $process: $count${NC}"
    fi
done

# 客户端连接分析
echo -e "\n${BLUE}=== 客户端连接分析 ===${NC}"
total_connections=$(ps auxww | grep "postgres:" | grep -E "(idle|SELECT|INSERT|UPDATE|DELETE)" | grep -v grep | wc -l)
echo "总连接数: $total_connections"

if [ $total_connections -gt $MAX_CONNECTIONS ]; then
    echo -e "${RED}⚠️  连接数超过阈值 ($MAX_CONNECTIONS)${NC}"
fi

# 按状态分组
echo -e "\n${YELLOW}按状态分组:${NC}"
for status in "idle" "SELECT" "INSERT" "UPDATE" "DELETE" "waiting" "idle in transaction"; do
    count=$(ps auxww | grep "postgres:" | grep "$status" | grep -v grep | wc -l)
    if [ $count -gt 0 ]; then
        if [ "$status" = "waiting" ]; then
            echo -e "  ${RED}$status: $count${NC}"
        elif [ "$status" = "idle in transaction" ]; then
            echo -e "  ${YELLOW}$status: $count${NC}"
        else
            echo -e "  ${GREEN}$status: $count${NC}"
        fi
    fi
done

# 资源使用警告
echo -e "\n${BLUE}=== 资源使用警告 ===${NC}"
ps auxww | grep "postgres:" | grep -v grep | while read line; do
    cpu=$(echo $line | awk '{print $3}' | cut -d. -f1)
    mem=$(echo $line | awk '{print $4}' | cut -d. -f1)
    pid=$(echo $line | awk '{print $2}')
    process_info=$(echo $line | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}')

    if [ $cpu -gt $HIGH_CPU_THRESHOLD ]; then
        echo -e "${RED}🔥 高CPU使用: PID $pid (${cpu}%) - $process_info${NC}"
    fi

    if [ $mem -gt $HIGH_MEM_THRESHOLD ]; then
        echo -e "${RED}💾 高内存使用: PID $pid (${mem}%) - $process_info${NC}"
    fi
done

故障排查指南 ​

常见问题与解决方案 ​

1. 进程数量异常 ​

bash
# 检查进程数量
ps auxww | grep postgres | grep -v grep | wc -l

# 如果进程数量过多,检查连接池配置
# 查看 max_connections 设置
psql -c "SHOW max_connections;"

2. 锁等待过多 ​

bash
# 查找等待锁的进程
ps auxww | grep "waiting" | grep postgres

# 在数据库中查看锁信息
psql -c "SELECT * FROM pg_locks WHERE NOT granted;"

3. 长时间运行的事务 ​

bash
# 找出长时间运行的事务
ps auxww | grep "idle in transaction" | grep postgres

# 在数据库中查看事务时间
psql -c "SELECT pid, now() - pg_stat_activity.query_start AS duration, query
         FROM pg_stat_activity
         WHERE state = 'idle in transaction'
         AND now() - pg_stat_activity.query_start > interval '5 minutes';"

最佳实践 ​

监控最佳实践

  1. 定期监控: 建立定期的进程监控机制,及时发现异常
  2. 设置告警: 对关键指标设置阈值告警
  3. 记录历史: 保存监控历史数据,便于问题追踪
  4. 自动化处理: 对常见问题建立自动化处理机制
  5. 文档化: 记录常见问题的处理方法 :::

通过这些监控技术和工具,数据库管理员可以有效地监控 PostgreSQL 数据库的运行状态,及时发现并解决性能问题,确保数据库系统的稳定运行。