Skip to content

PostgreSQL 服务器关闭完全指南

概述

PostgreSQL 数据库服务器关闭是运维工作中的重要环节,正确的关闭方式能确保数据完整性、避免数据丢失,并为下次启动做好准备。本指南将详细介绍 PostgreSQL 服务器关闭的各种方法、应用场景和最佳实践。

关闭方式概览

PostgreSQL 提供了三种主要的服务器关闭模式,每种模式适用于不同的业务场景:

关闭模式信号处理方式适用场景关闭时间
智能关闭SIGTERM等待所有会话正常结束计划性维护、正常关闭较长
快速关闭SIGINT中止当前事务,立即退出紧急维护、快速重启中等
立即关闭SIGQUIT强制终止所有进程紧急故障处理最短

详细关闭模式解析

1. 智能关闭 (SIGTERM)

智能关闭是最安全的关闭方式,适用于计划性维护和正常业务关闭场景。

业务场景示例

场景:电商网站晚间维护窗口

某电商网站需要在晚上 2:00-4:00 进行数据库维护,要确保所有用户的订单事务都能正常完成。

智能关闭会等待所有正在进行的事务完成,确保数据一致性,但关闭时间可能较长。 :::

实现方法

bash
# 智能关闭数据库服务器
pg_ctl stop -D /usr/local/pgsql/data -m smart

# 带超时的智能关闭(60秒超时)
pg_ctl stop -D /usr/local/pgsql/data -m smart -t 60
bash
# 获取postgres主进程PID
PID=$(head -1 /usr/local/pgsql/data/postmaster.pid)

# 发送SIGTERM信号
kill -TERM $PID

# 或者直接使用
kill -15 $PID
bash
# 如果使用systemd管理
sudo systemctl stop postgresql

# 查看关闭状态
sudo systemctl status postgresql

监控关闭过程

sql
-- 在关闭过程中监控活跃连接
SELECT
    pid,
    usename,
    application_name,
    client_addr,
    state,
    query_start,
    query
FROM pg_stat_activity
WHERE state = 'active';

输出示例:

 pid  | usename |  application_name  | client_addr |  state  |         query_start         | query
------+---------+--------------------+-------------+---------+-----------------------------+-------
 1234 | webapp  | order_service      | 10.0.1.100  | active  | 2024-01-15 02:01:30.123+08 | INSERT INTO orders...
 1235 | report  | analytics_tool     | 10.0.1.101  | active  | 2024-01-15 02:01:25.456+08 | SELECT * FROM sales...

完整关闭脚本

bash
#!/bin/bash
# smart_shutdown.sh - 智能关闭PostgreSQL服务器

PGDATA="/usr/local/pgsql/data"
LOGFILE="/var/log/postgresql/shutdown.log"
TIMEOUT=300  # 5分钟超时

echo "$(date): 开始智能关闭PostgreSQL服务器..." >> $LOGFILE

# 检查当前连接数
ACTIVE_CONNECTIONS=$(psql -t -c "SELECT count(*) FROM pg_stat_activity WHERE state = 'active';")
echo "$(date): 当前活跃连接数: $ACTIVE_CONNECTIONS" >> $LOGFILE

# 执行智能关闭
pg_ctl stop -D $PGDATA -m smart -t $TIMEOUT

if [ $? -eq 0 ]; then
    echo "$(date): PostgreSQL服务器已成功关闭" >> $LOGFILE
else
    echo "$(date): PostgreSQL服务器关闭超时,请检查" >> $LOGFILE
    exit 1
fi

2. 快速关闭 (SIGINT)

快速关闭适用于需要尽快重启数据库但又不想等待长时间事务完成的场景。

业务场景示例

场景:应用程序内存泄漏紧急处理

生产环境中发现某个应用程序存在内存泄漏,导致数据库连接异常,需要快速重启数据库服务。

快速关闭会中止正在进行的事务,可能导致部分数据操作失败,需要谨慎使用。

实现方法

bash
# 快速关闭数据库服务器
pg_ctl stop -D /usr/local/pgsql/data -m fast

# 快速关闭并立即重启
pg_ctl restart -D /usr/local/pgsql/data -m fast
bash
# 获取postgres主进程PID并发送SIGINT信号
kill -INT $(head -1 /usr/local/pgsql/data/postmaster.pid)
bash
#!/bin/bash
# fast_restart.sh - 快速重启PostgreSQL

echo "警告:即将执行快速关闭,当前事务将被中止"
read -p "是否继续?(y/N): " confirm

if [[ $confirm == [yY] ]]; then
    echo "执行快速关闭..."
    pg_ctl stop -D /usr/local/pgsql/data -m fast

    echo "等待关闭完成..."
    sleep 3

    echo "重新启动PostgreSQL..."
    pg_ctl start -D /usr/local/pgsql/data -l /var/log/postgresql/postgresql.log

    echo "PostgreSQL已重启"
else
    echo "操作已取消"
fi

关闭后的状态检查

sql
-- 重启后检查是否有未完成的事务需要恢复
SELECT
    datname,
    xact_commit,
    xact_rollback,
    blks_read,
    blks_hit
FROM pg_stat_database
WHERE datname NOT IN ('template0', 'template1');

3. 立即关闭 (SIGQUIT)

立即关闭是最激进的关闭方式,仅在紧急情况下使用。

业务场景示例

场景:系统资源严重不足

服务器磁盘空间即将耗尽,或者内存不足导致系统响应缓慢,需要立即关闭数据库以释放资源。

立即关闭会跳过正常的数据库关闭处理,下次启动时需要进行 WAL 日志恢复,可能耗时较长。

实现方法

bash
# 立即关闭(谨慎使用)
pg_ctl stop -D /usr/local/pgsql/data -m immediate

# 或使用kill命令
kill -QUIT $(head -1 /usr/local/pgsql/data/postmaster.pid)

立即关闭后的恢复过程

工具和命令详解

pg_ctl 命令详解

pg_ctl 是 PostgreSQL 提供的服务器控制工具,提供了统一的接口来管理数据库服务器。

基本语法

bash
pg_ctl stop [选项] [-D 数据目录]

常用选项

选项说明示例
-D datadir指定数据目录-D /usr/local/pgsql/data
-m mode指定关闭模式-m smart|fast|immediate
-t timeout设置超时时间(秒)-t 60
-l logfile指定日志文件-l /var/log/postgresql.log
-W不等待操作完成-W

实用示例

bash
# 查看服务器状态
pg_ctl status -D /usr/local/pgsql/data

# 重新加载配置文件
pg_ctl reload -D /usr/local/pgsql/data

# 显示详细信息
pg_ctl status -D /usr/local/pgsql/data -V
bash
# 带日志的启动
pg_ctl start -D /usr/local/pgsql/data -l /var/log/postgresql/server.log

# 条件重启(如果运行中则重启,否则启动)
pg_ctl restart -D /usr/local/pgsql/data -m fast

# 静默操作(不显示输出)
pg_ctl stop -D /usr/local/pgsql/data -m smart -s

使用 kill 命令

在某些情况下,直接使用系统的 kill 命令可能更直接和灵活。

获取进程 ID

bash
# 方法1:从postmaster.pid文件读取
PID=$(head -1 /usr/local/pgsql/data/postmaster.pid)
echo "PostgreSQL主进程PID: $PID"

# 方法2:使用ps命令查找
ps aux | grep postgres | grep -v grep

# 方法3:使用pgrep命令
pgrep -f "postgres.*postmaster"

发送信号示例

bash
#!/bin/bash
# signal_demo.sh - 演示不同信号的发送

PIDFILE="/usr/local/pgsql/data/postmaster.pid"

if [ ! -f "$PIDFILE" ]; then
    echo "错误:找不到postmaster.pid文件,PostgreSQL可能未运行"
    exit 1
fi

PID=$(head -1 $PIDFILE)
echo "PostgreSQL主进程PID: $PID"

echo "选择关闭模式:"
echo "1) 智能关闭 (SIGTERM)"
echo "2) 快速关闭 (SIGINT)"
echo "3) 立即关闭 (SIGQUIT)"
read -p "请输入选择 (1-3): " choice

case $choice in
    1)
        echo "执行智能关闭..."
        kill -TERM $PID
        ;;
    2)
        echo "执行快速关闭..."
        kill -INT $PID
        ;;
    3)
        echo "执行立即关闭..."
        read -p "确认执行立即关闭?(y/N): " confirm
        if [[ $confirm == [yY] ]]; then
            kill -QUIT $PID
        else
            echo "操作已取消"
        fi
        ;;
    *)
        echo "无效选择"
        exit 1
        ;;
esac

单个会话管理

除了整个服务器的关闭,PostgreSQL 还提供了管理单个会话的功能。

查看活跃会话

sql
-- 查看所有活跃会话
SELECT
    pid,
    usename AS 用户名,
    application_name AS 应用名称,
    client_addr AS 客户端地址,
    client_port AS 客户端端口,
    backend_start AS 连接开始时间,
    state AS 状态,
    query AS 当前查询
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY backend_start;

终止特定会话

使用 SQL 函数

sql
-- 温和终止会话(相当于发送SIGTERM)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'problem_user'
AND state = 'active';

-- 取消正在运行的查询(不断开连接)
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE query LIKE '%long_running_query%';

批量会话管理

sql
-- 创建会话管理函数
CREATE OR REPLACE FUNCTION terminate_user_sessions(target_user TEXT)
RETURNS TABLE(terminated_pid INTEGER, success BOOLEAN) AS $$
BEGIN
    RETURN QUERY
    SELECT
        a.pid,
        pg_terminate_backend(a.pid) as success
    FROM pg_stat_activity a
    WHERE a.usename = target_user
    AND a.pid != pg_backend_pid()  -- 不终止当前会话
    AND a.state != 'idle';
END;
$$ LANGUAGE plpgsql;

-- 使用示例
SELECT * FROM terminate_user_sessions('webapp_user');

最佳实践和注意事项

1. 安全关闭检查清单

关闭前检查清单
  • 确认是否有重要的长时间运行事务
  • 检查备份任务是否正在运行
  • 通知相关应用程序即将维护
  • 确保有足够的恢复时间窗口
  • 准备回滚计划 :::
bash
#!/bin/bash
# pre_shutdown_check.sh - 关闭前安全检查

echo "=== PostgreSQL 关闭前安全检查 ==="

# 检查活跃连接数
ACTIVE_CONN=$(psql -t -c "SELECT count(*) FROM pg_stat_activity WHERE state = 'active';")
echo "活跃连接数: $ACTIVE_CONN"

# 检查长时间运行的事务
LONG_TRANS=$(psql -t -c "
SELECT count(*) FROM pg_stat_activity
WHERE state = 'active'
AND query_start < now() - interval '5 minutes';")
echo "运行超过5分钟的事务: $LONG_TRANS"

# 检查是否有备份在运行
BACKUP_RUNNING=$(ps aux | grep -c 'pg_dump\|pg_basebackup' | grep -v grep)
echo "正在运行的备份任务: $BACKUP_RUNNING"

# 检查复制状态
REPL_STATUS=$(psql -t -c "SELECT count(*) FROM pg_stat_replication;")
echo "活跃复制连接: $REPL_STATUS"

if [ $LONG_TRANS -gt 0 ] || [ $BACKUP_RUNNING -gt 0 ]; then
    echo ""
    echo "警告:检测到长时间运行的事务或备份任务"
    echo "建议等待这些操作完成后再关闭服务器"
    exit 1
else
    echo ""
    echo "检查通过,可以安全关闭服务器"
fi

2. 关闭模式选择指南

3. 监控和日志

关闭过程监控脚本

bash
#!/bin/bash
# monitor_shutdown.sh - 监控PostgreSQL关闭过程

PGDATA="/usr/local/pgsql/data"
LOGFILE="/var/log/postgresql/shutdown_monitor.log"

echo "$(date): 开始监控PostgreSQL关闭过程..." >> $LOGFILE

# 持续监控直到服务器完全关闭
while pg_ctl status -D $PGDATA > /dev/null 2>&1; do
    # 记录当前连接数
    CONNECTIONS=$(psql -t -c "SELECT count(*) FROM pg_stat_activity;" 2>/dev/null || echo "0")
    echo "$(date): 剩余连接数: $CONNECTIONS" >> $LOGFILE

    # 记录活跃事务
    ACTIVE_TRANS=$(psql -t -c "SELECT count(*) FROM pg_stat_activity WHERE state = 'active';" 2>/dev/null || echo "0")
    echo "$(date): 活跃事务数: $ACTIVE_TRANS" >> $LOGFILE

    sleep 2
done

echo "$(date): PostgreSQL服务器已完全关闭" >> $LOGFILE

4. 常见问题和解决方案

问题 1:智能关闭时间过长

原因分析:

  • 存在长时间运行的事务
  • 有空闲事务占用连接
  • 应用程序没有正确释放连接

解决方案:

sql
-- 查找长时间运行的事务
SELECT
    pid,
    usename,
    query_start,
    state,
    extract(epoch from (now() - query_start)) as duration_seconds,
    query
FROM pg_stat_activity
WHERE state != 'idle'
AND query_start < now() - interval '30 seconds'
ORDER BY query_start;

-- 如果需要,可以终止特定的长时间事务
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'active'
AND query_start < now() - interval '5 minutes';

问题 2:关闭后重启失败

原因分析:

  • 立即关闭导致数据文件损坏
  • WAL 日志恢复失败
  • 权限或配置问题

解决方案:

bash
#!/bin/bash
# recovery_check.sh - 重启失败诊断

PGDATA="/usr/local/pgsql/data"
LOGFILE="$PGDATA/log/postgresql-$(date +%Y-%m-%d).log"

echo "=== PostgreSQL 重启失败诊断 ==="

# 检查数据目录权限
echo "检查数据目录权限..."
ls -la $PGDATA

# 检查磁盘空间
echo "检查磁盘空间..."
df -h $PGDATA

# 检查最新的错误日志
echo "最近的错误日志:"
if [ -f "$LOGFILE" ]; then
    tail -20 "$LOGFILE"
else
    echo "找不到日志文件: $LOGFILE"
fi

# 尝试以单用户模式启动进行恢复
echo "尝试单用户模式启动..."
postgres --single -D $PGDATA template1 < /dev/null

总结

PostgreSQL 服务器关闭是数据库管理的重要组成部分,正确选择关闭模式对于保证数据安全和系统稳定性至关重要:

  • 智能关闭 (SIGTERM):适用于计划性维护,确保数据完整性
  • 快速关闭 (SIGINT):适用于紧急情况,平衡速度和安全性
  • 立即关闭 (SIGQUIT):仅用于极端紧急情况,需要后续恢复

在生产环境中,建议优先使用智能关闭,只有在时间紧迫或系统异常时才考虑其他关闭模式。始终在关闭前进行必要的检查,并准备好恢复方案。

通过合理使用这些关闭方法和监控工具,可以确保 PostgreSQL 数据库的安全、稳定运行。