Appearance
数据库服务器启动
PostgreSQL 数据库服务器的启动和管理是数据库管理员必须掌握的核心技能。本章详细介绍如何启动 PostgreSQL 服务器、配置自动启动,以及解决常见的启动和连接问题。
服务器启动概述
在任何客户端访问数据库之前,必须首先启动 PostgreSQL 数据库服务器。服务器的核心程序名为 postgres
,它负责处理所有数据库请求、管理连接和维护数据一致性。
业务场景
在实际业务环境中,PostgreSQL 服务器启动涉及多个场景:
- 开发环境:开发人员需要在本地启动数据库进行应用开发和测试
- 生产环境:服务器需要随系统启动自动运行,保证高可用性
- 容器化部署:在 Docker 或 Kubernetes 环境中管理数据库服务
- 故障恢复:系统故障后快速恢复数据库服务
手动启动服务器
前台启动
最基本的启动方式是直接调用 postgres
程序:
bash
# 基本启动命令,指定数据目录
$ postgres -D /usr/local/pgsql/data
前台启动的特点:
- 服务器在当前终端会话中运行
- 所有日志信息直接显示在终端
- 适用于调试和故障排查
- 终端关闭时服务器会停止
完整示例:开发环境启动
bash
# 场景:开发人员在本地启动数据库进行开发测试
# 1. 切换到 postgres 用户(如果需要)
sudo su - postgres
# 2. 设置数据目录环境变量(可选)
export PGDATA=/usr/local/pgsql/data
# 3. 前台启动服务器
postgres -D /usr/local/pgsql/data
# 输出示例:
# 2024-06-08 10:30:15.123 CST [12345] LOG: starting PostgreSQL 15.3
# 2024-06-08 10:30:15.124 CST [12345] LOG: listening on IPv4 address "127.0.0.1", port 5432
# 2024-06-08 10:30:15.125 CST [12345] LOG: database system is ready to accept connections
后台启动
生产环境中通常需要后台运行服务器:
bash
# 后台启动并重定向日志
$ postgres -D /usr/local/pgsql/data >logfile 2>&1 &
语法解析:
>logfile
:将标准输出重定向到日志文件2>&1
:将标准错误也重定向到同一文件&
:在后台运行进程
完整示例:生产环境后台启动
bash
# 场景:在生产服务器上启动 PostgreSQL 服务
# 1. 创建日志目录
sudo mkdir -p /var/log/postgresql
sudo chown postgres:postgres /var/log/postgresql
# 2. 以 postgres 用户身份启动服务器
sudo su - postgres -c "postgres -D /usr/local/pgsql/data >/var/log/postgresql/server.log 2>&1 &"
# 3. 验证服务器启动状态
ps aux | grep postgres
# 输出示例:
# postgres 12345 0.1 2.3 123456 45678 ? S 10:30 0:00 postgres: main process
# postgres 12346 0.0 0.5 12345 6789 ? Ss 10:30 0:00 postgres: checkpointer
使用 pg_ctl 管理服务器
pg_ctl
是 PostgreSQL 提供的服务器管理工具,简化了启动、停止和重启操作。
基本用法
bash
# 启动服务器
pg_ctl start -l logfile
# 停止服务器
pg_ctl stop
# 重启服务器
pg_ctl restart
# 重载配置
pg_ctl reload
# 查看状态
pg_ctl status
详细示例
bash
# 场景:使用 pg_ctl 管理开发环境数据库
# 1. 启动服务器并指定数据目录和日志文件
pg_ctl start -D /usr/local/pgsql/data -l /var/log/postgresql/server.log
# 输出:
# waiting for server to start.... done
# server started
# 2. 检查服务器状态
pg_ctl status -D /usr/local/pgsql/data
# 输出:
# pg_ctl: server is running (PID: 12345)
# /usr/local/pgsql/bin/postgres "-D" "/usr/local/pgsql/data"
# 3. 重载配置文件(不重启服务器)
pg_ctl reload -D /usr/local/pgsql/data
# 输出:
# server signaled
# 4. 停止服务器
pg_ctl stop -D /usr/local/pgsql/data
# 输出:
# waiting for server to shut down.... done
# server stopped
系统自动启动配置
启动方式对比
操作系统 | 推荐方式 | 配置文件位置 | 特点 |
---|---|---|---|
Linux (systemd) | systemd 服务单元 | /etc/systemd/system/ | 现代化管理,支持依赖关系 |
Linux (传统) | init 脚本 | /etc/rc.d/rc.local | 简单直接,兼容性好 |
FreeBSD | rc 脚本 | /usr/local/etc/rc.d/ | 系统原生支持 |
macOS | launchd | /Library/LaunchDaemons/ | 系统服务管理 |
Linux systemd 配置
创建 systemd 服务单元文件是现代 Linux 系统的推荐方式:
ini
# 文件路径:/etc/systemd/system/postgresql.service
[Unit]
Description=PostgreSQL database server # 服务描述
Documentation=man:postgres(1) # 文档引用
After=network-online.target # 启动依赖:网络就绪后启动
Wants=network-online.target # 弱依赖:建议网络可用
[Service]
Type=notify # 服务类型:支持启动通知
User=postgres # 运行用户
ExecStart=/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data # 启动命令
ExecReload=/bin/kill -HUP $MAINPID # 重载命令:发送 HUP 信号
KillMode=mixed # 停止模式:混合模式
KillSignal=SIGINT # 停止信号:中断信号
TimeoutSec=infinity # 超时时间:无限制(防止恢复超时)
[Install]
WantedBy=multi-user.target # 安装目标:多用户模式
部署和管理示例:
bash
# 场景:在 CentOS/RHEL 服务器上配置 PostgreSQL 自动启动
# 1. 创建服务单元文件
sudo tee /etc/systemd/system/postgresql.service > /dev/null <<EOF
[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=postgres
ExecStart=/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutSec=infinity
[Install]
WantedBy=multi-user.target
EOF
# 2. 重载 systemd 配置
sudo systemctl daemon-reload
# 3. 启用自动启动
sudo systemctl enable postgresql
# 输出:
# Created symlink /etc/systemd/system/multi-user.target.wants/postgresql.service
# 4. 启动服务
sudo systemctl start postgresql
# 5. 检查服务状态
sudo systemctl status postgresql
# 输出示例:
# ● postgresql.service - PostgreSQL database server
# Loaded: loaded (/etc/systemd/system/postgresql.service; enabled; vendor preset: disabled)
# Active: active (running) since Sat 2024-06-08 10:30:15 CST; 2min ago
# Main PID: 12345 (postgres)
# Status: "ready to accept connections"
传统 Linux 启动脚本
对于不使用 systemd 的系统:
bash
# 添加到 /etc/rc.d/rc.local 或 /etc/rc.local
/usr/local/pgsql/bin/pg_ctl start -l /var/log/postgresql/server.log -D /usr/local/pgsql/data
# 或者使用 su 切换用户
su postgres -c 'pg_ctl start -D /usr/local/pgsql/data -l /var/log/postgresql/server.log'
其他操作系统配置
bash
# 使用 PostgreSQL 提供的启动脚本
# 查看:contrib/start-scripts/freebsd
# 或添加到 /etc/rc.local
if [ -x /usr/local/pgsql/bin/pg_ctl ]; then
su -l postgres -c '/usr/local/pgsql/bin/pg_ctl start -s -l /var/log/postgresql/server.log -D /usr/local/pgsql/data'
echo -n ' postgresql'
fi
bash
# 添加到 /etc/rc.local
if [ -x /usr/local/pgsql/bin/pg_ctl -a -x /usr/local/pgsql/bin/postgres ]; then
su -l postgres -c '/usr/local/pgsql/bin/pg_ctl start -s -l /var/postgresql/log -D /usr/local/pgsql/data'
echo -n ' postgresql'
fi
bash
# 创建 /etc/init.d/postgresql
su - postgres -c "/usr/local/pgsql/bin/pg_ctl start -l logfile -D /usr/local/pgsql/data"
# 创建符号链接
ln -s /etc/init.d/postgresql /etc/rc3.d/S99postgresql
服务器进程管理
PID 文件
PostgreSQL 服务器运行时会创建一个 PID 文件用于进程管理:
bash
# PID 文件位置
/usr/local/pgsql/data/postmaster.pid
# 查看文件内容
cat /usr/local/pgsql/data/postmaster.pid
PID 文件内容示例:
12345 # 主进程 PID
/usr/local/pgsql/data # 数据目录
1686201015 # 启动时间戳
5432 # 端口号
/tmp # Unix 套接字目录
localhost # 监听地址
12345001 4325678 # 共享内存段 ID
进程架构
常见启动失败问题
端口冲突问题
错误信息:
LOG: could not bind IPv4 address "127.0.0.1": Address already in use
HINT: Is another postmaster already running on port 5432? If not, wait a few seconds and retry.
FATAL: could not create any TCP/IP sockets
原因分析:
- 指定端口已被占用(通常是另一个 PostgreSQL 实例)
- 权限不足(尝试使用保留端口)
解决方案:
bash
# 场景:解决端口冲突问题
# 1. 检查端口占用情况
sudo netstat -tlnp | grep 5432
# 或者使用 ss 命令
sudo ss -tlnp | grep 5432
# 输出示例:
# tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 12345/postgres
# 2. 检查是否有其他 PostgreSQL 进程
ps aux | grep postgres
# 3. 如果有僵尸进程,清理 PID 文件
sudo rm /usr/local/pgsql/data/postmaster.pid
# 4. 或者使用不同端口启动
postgres -D /usr/local/pgsql/data -p 5433
# 5. 永久修改端口配置
echo "port = 5433" >> /usr/local/pgsql/data/postgresql.conf
权限相关的端口问题:
bash
# 尝试使用保留端口(<1024)时的错误
$ postgres -p 666
LOG: could not bind IPv4 address "127.0.0.1": Permission denied
HINT: Is another postmaster already running on port 666? If not, wait a few seconds and retry.
FATAL: could not create any TCP/IP sockets
# 解决方案:使用非保留端口或以 root 身份运行(不推荐)
postgres -p 5432 # 使用标准端口
共享内存问题
错误信息:
FATAL: could not create shared memory segment: Invalid argument
DETAIL: Failed system call was shmget(key=5440001, size=4011376640, 03600).
原因分析:
- 系统共享内存限制小于 PostgreSQL 需求
- 只在
shared_memory_type = sysv
时出现
解决方案:
bash
# 场景:解决共享内存限制问题
# 1. 查看当前系统限制
ipcs -l
# 输出示例:
# ------ Shared Memory Limits --------
# max number of segments = 4096
# max seg size (kbytes) = 67108864
# max total shared memory (kbytes) = 17179869184
# 2. 查看 PostgreSQL 配置
grep shared_buffers /usr/local/pgsql/data/postgresql.conf
# 3. 临时降低缓冲区大小
postgres -D /usr/local/pgsql/data -c shared_buffers=128MB
# 4. 永久修改配置文件
sed -i 's/shared_buffers = .*/shared_buffers = 128MB/' /usr/local/pgsql/data/postgresql.conf
# 5. 或者增加系统限制(需要 root 权限)
echo "kernel.shmmax = 17179869184" >> /etc/sysctl.conf
echo "kernel.shmall = 4194304" >> /etc/sysctl.conf
sysctl -p
信号量限制问题
错误信息:
FATAL: could not create semaphores: No space left on device
DETAIL: Failed system call was semget(5440126, 17, 03600).
解决方案:
bash
# 场景:解决信号量限制问题
# 1. 查看当前信号量使用情况
ipcs -s
# 2. 查看系统限制
cat /proc/sys/kernel/sem
# 输出格式:SEMMSL SEMMNS SEMOPM SEMMNI
# 示例:250 32000 32 128
# 3. 临时减少连接数
postgres -D /usr/local/pgsql/data -c max_connections=50
# 4. 增加系统信号量限制
echo "kernel.sem = 250 512000 32 256" >> /etc/sysctl.conf
sysctl -p
# 5. 验证修改
cat /proc/sys/kernel/sem
系统限制对比表
参数 | 描述 | 建议值 | 检查命令 |
---|---|---|---|
SHMMAX | 单个共享内存段最大字节数 | 系统内存的 50% | cat /proc/sys/kernel/shmmax |
SHMALL | 系统共享内存总页数 | SHMMAX/页大小 | cat /proc/sys/kernel/shmall |
SEMMNI | 系统信号量集合数 | 至少 128 | cat /proc/sys/kernel/sem |
SEMMNS | 系统信号量总数 | 32000 以上 | cat /proc/sys/kernel/sem |
客户端连接问题
TCP/IP 连接失败
错误信息:
psql: error: connection to server at "server.joe.com" (123.123.123.123), port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?
排查流程:
详细排查步骤:
bash
# 场景:客户端无法连接到 PostgreSQL 服务器
# 1. 验证服务器是否运行
sudo systemctl status postgresql
# 或者
ps aux | grep postgres
# 2. 检查服务器监听状态
sudo netstat -tlnp | grep 5432
# 输出示例:
# tcp 0 0 0.0.0.0:5432 0.0.0.0:* LISTEN 12345/postgres
# 3. 检查监听地址配置
grep listen_addresses /usr/local/pgsql/data/postgresql.conf
# 确保包含客户端 IP 或设置为 '*'
# 4. 测试网络连通性
telnet server.joe.com 5432
# 或者
nc -zv server.joe.com 5432
# 5. 检查防火墙规则
sudo iptables -L | grep 5432
# 或在 CentOS/RHEL 上
sudo firewall-cmd --list-ports
# 6. 添加防火墙规则(如果需要)
sudo firewall-cmd --permanent --add-port=5432/tcp
sudo firewall-cmd --reload
Unix 域套接字连接问题
错误信息:
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
解决方案:
bash
# 场景:本地套接字连接问题
# 1. 检查套接字文件是否存在
ls -la /tmp/.s.PGSQL.5432
# 2. 检查服务器套接字配置
grep unix_socket_directories /usr/local/pgsql/data/postgresql.conf
# 输出示例:
# unix_socket_directories = '/tmp, /var/run/postgresql'
# 3. 确认客户端使用正确的套接字路径
psql -h /tmp -p 5432
# 4. 检查套接字目录权限
ls -ld /tmp
# 应该是 drwxrwxrwt
# 5. 如果套接字目录不存在,创建它
sudo mkdir -p /var/run/postgresql
sudo chown postgres:postgres /var/run/postgresql
sudo chmod 755 /var/run/postgresql
连接故障排查工具
诊断脚本示例
bash
#!/bin/bash
# PostgreSQL 连接诊断脚本
echo "=== PostgreSQL 连接诊断 ==="
echo
# 1. 检查服务器进程
echo "1. 检查 PostgreSQL 进程:"
if pgrep -f postgres > /dev/null; then
echo "✓ PostgreSQL 进程正在运行"
ps aux | grep "[p]ostgres" | head -5
else
echo "✗ PostgreSQL 进程未运行"
fi
echo
# 2. 检查端口监听
echo "2. 检查端口监听:"
if netstat -tlnp 2>/dev/null | grep -q ":5432"; then
echo "✓ 端口 5432 正在监听"
netstat -tlnp | grep ":5432"
else
echo "✗ 端口 5432 未监听"
fi
echo
# 3. 检查套接字文件
echo "3. 检查 Unix 域套接字:"
if [ -S "/tmp/.s.PGSQL.5432" ]; then
echo "✓ Unix 域套接字存在"
ls -la /tmp/.s.PGSQL.5432
else
echo "✗ Unix 域套接字不存在"
fi
echo
# 4. 尝试连接测试
echo "4. 连接测试:"
if command -v psql > /dev/null; then
if psql -h localhost -p 5432 -U postgres -c "SELECT version();" 2>/dev/null | grep -q PostgreSQL; then
echo "✓ 数据库连接成功"
else
echo "✗ 数据库连接失败"
fi
else
echo "? psql 客户端未安装"
fi
性能监控
bash
# 监控 PostgreSQL 服务器状态的有用命令
# 1. 查看活动连接
psql -c "SELECT pid, usename, application_name, client_addr, state
FROM pg_stat_activity WHERE state = 'active';"
# 2. 查看数据库大小
psql -c "SELECT datname, pg_size_pretty(pg_database_size(datname))
FROM pg_database;"
# 3. 查看表空间使用情况
psql -c "SELECT spcname, pg_size_pretty(pg_tablespace_size(spcname))
FROM pg_tablespace;"
# 4. 查看锁等待情况
psql -c "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
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
JOIN pg_catalog.pg_stat_activity blocking_activity
ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;"
最佳实践总结
启动配置建议
TIP
生产环境建议
- 使用 systemd 服务:现代 Linux 系统首选 systemd 管理
- 配置合适的超时:设置
TimeoutSec=infinity
防止恢复超时 - 日志重定向:确保日志输出到指定文件便于监控
- 资源限制:根据硬件配置调整内存和连接数参数
- 监控进程:设置监控脚本检查服务器健康状态
安全注意事项
WARNING
安全提醒
- 用户权限:始终使用
postgres
用户运行服务器,避免使用root
- 网络配置:仔细配置
listen_addresses
和pg_hba.conf
- 防火墙规则:只开放必要的端口给授权的客户端
- 文件权限:确保数据目录和配置文件有适当的权限设置
故障预防
检查项目 | 频率 | 检查内容 |
---|---|---|
磁盘空间 | 每日 | 数据目录、日志目录、临时目录空间 |
内存使用 | 每日 | 共享内存、缓冲区使用情况 |
连接数 | 每小时 | 活动连接数是否接近限制 |
日志错误 | 实时 | 监控错误日志和警告信息 |
备份状态 | 每日 | 确认备份任务正常执行 |
通过掌握这些 PostgreSQL 服务器启动和管理技能,您可以确保数据库服务的稳定运行和高可用性。记住始终根据具体的业务需求和环境特点选择合适的启动和管理方式。