1. 项目背景与核心挑战
在金融、政务等对数据可靠性要求极高的领域,PostgreSQL高可用集群的离线部署是个硬需求。去年我们给某省级医保系统做迁移时就遇到了这个典型场景——内网环境不允许连接外网,但又要保证数据库服务99.99%的可用性。
离线部署的核心痛点在于:
- 依赖包像俄罗斯套娃一样层层嵌套
- 高可用组件间的版本兼容性像定时炸弹
- 没有互联网的情况下调试就像蒙眼走钢丝
2. 离线环境准备工作
2.1 依赖包全量下载
在能联网的跳板机上执行这个组合命令,可以一次性抓取所有依赖:
bash复制apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances \
postgresql-15 repmgr patroni keepalived haproxy | grep "^\w" | sort -u)
关键技巧:
- 使用
--no-recommends避免下载非必要包 - 按
postgresql-15 repmgr patroni keepalived haproxy顺序处理,确保基础依赖先下载 - 最终得到的.deb文件建议按组件分类存放
2.2 离线安装包制作
我们采用自制脚本自动生成安装清单:
python复制#!/usr/bin/env python3
import subprocess
from pathlib import Path
def scan_deps(pkg_path):
result = subprocess.run(['dpkg-deb', '-f', pkg_path, 'Depends'],
capture_output=True, text=True)
return result.stdout.strip().split(', ')
def build_dependency_tree(root_pkg):
tree = {}
queue = [root_pkg]
while queue:
current = queue.pop(0)
if current not in tree:
deps = scan_deps(current)
tree[current] = deps
queue.extend(deps)
return tree
这个脚本会分析.deb包的递归依赖关系,生成完整的安装顺序列表。实测比手动整理效率提升10倍以上。
3. 集群部署实战
3.1 节点初始化配置
每个节点需要调整的sysctl参数:
bash复制# 共享内存设置(建议物理内存的25%)
echo "kernel.shmmax = 17179869184" >> /etc/sysctl.conf
echo "kernel.shmall = 4194304" >> /etc/sysctl.conf
# 网络优化
echo "net.core.rmem_max = 4194304" >> /etc/sysctl.conf
echo "net.core.wmem_max = 4194304" >> /etc/sysctl.conf
重要提示:必须在安装PostgreSQL前设置这些参数,否则需要重启才能生效
3.2 多节点同步安装
使用ansible离线安装的playbook示例:
yaml复制- hosts: db_nodes
tasks:
- name: Transfer deb packages
copy:
src: "/opt/offline_pkgs/{{ item }}"
dest: "/var/cache/apt/archives/"
loop: "{{ lookup('file', 'pkg_list.txt').splitlines() }}"
- name: Install packages
apt:
deb: "/var/cache/apt/archives/{{ item }}"
loop: "{{ lookup('file', 'install_order.txt').splitlines() }}"
这个方案比逐台手动安装效率提升显著,50台节点集群部署时间从8小时缩短到40分钟。
4. 高可用架构实现
4.1 Patroni配置模板
关键配置项说明:
yaml复制restapi:
listen: 0.0.0.0:8008
connect_address: {{ ansible_default_ipv4.address }}:8008
etcd:
hosts:
- 10.0.0.1:2379
- 10.0.0.2:2379
- 10.0.0.3:2379
postgresql:
name: pg_node_{{ node_id }}
listen: 0.0.0.0:5432
connect_address: {{ ansible_default_ipv4.address }}:5432
data_dir: /var/lib/postgresql/15/main
pgpass: /var/lib/postgresql/.pgpass
parameters:
max_connections: 500
shared_buffers: 8GB
wal_level: logical
4.2 脑裂防护方案
我们采用三级防护机制:
- Patroni自带的leader锁
- Keepalived的VIP漂移检测
- 自定义仲裁脚本:
bash复制#!/bin/bash
QUORUM=$(etcdctl endpoint status | grep -c 'true')
if [ $QUORUM -lt 2 ]; then
systemctl stop postgresql
exit 1
fi
这个组合方案在最近一次机房光纤中断事件中,成功避免了脑裂发生。
5. 验证与监控
5.1 故障转移测试
模拟主库宕机的正确姿势:
bash复制# 在主节点执行
systemctl stop postgresql
# 观察日志时间线
journalctl -u patroni -f
# 预期结果应该在30秒内完成切换
5.2 监控指标采集
离线环境推荐使用node_exporter+prometheus方案,需要特别注意:
- 提前下载好这些组件的静态编译版本
- 配置采集间隔调整为30秒(默认15秒可能压力过大)
- 关键监控项包括:
- WAL积压量
- 复制延迟
- 连接池使用率
6. 运维避坑指南
6.1 版本锁定策略
在/etc/apt/preferences.d/下创建postgresql.pref:
code复制Package: postgresql-*
Pin: version 15.3*
Pin-Priority: 1001
这个配置可以防止意外升级导致集群不一致。
6.2 备份恢复技巧
离线环境下的WAL归档方案:
bash复制# 在postgresql.conf中配置
archive_mode = on
archive_command = 'test ! -f /mnt/backup/wal/%f && cp %p /mnt/backup/wal/%f'
配合crontab定期校验备份完整性:
bash复制0 3 * * * pg_checksums -D /var/lib/postgresql/15/main --progress
7. 性能调优实战
7.1 内存分配优化
计算公式:
code复制shared_buffers = 总内存 × 0.25
work_mem = (总内存 - shared_buffers) / max_connections × 0.5
maintenance_work_mem = 总内存 × 0.05
示例:64GB内存的服务器配置:
yaml复制postgresql:
parameters:
shared_buffers: 16GB
work_mem: 32MB
maintenance_work_mem: 3GB
effective_cache_size: 48GB
7.2 磁盘IO优化
使用deadline调度器的配置方法:
bash复制echo deadline > /sys/block/sda/queue/scheduler
echo 1024 > /sys/block/sda/queue/nr_requests
对于SSD设备额外需要:
bash复制echo 1 > /sys/block/sda/queue/iosched/fifo_batch
8. 安全加固措施
8.1 网络隔离方案
建议的iptables规则:
bash复制# 只允许集群节点间通信
iptables -A INPUT -p tcp --dport 5432 -s 10.0.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 8008 -s 10.0.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 5432 -j DROP
8.2 审计日志配置
在postgresql.conf中添加:
yaml复制logging_collector = on
log_statement = 'ddl'
log_connections = on
log_disconnections = on
log_hostname = on
log_line_prefix = '%m [%p] %q%u@%d '
配合logrotate实现日志轮转:
bash复制/var/log/postgresql/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
sharedscripts
postrotate
/bin/systemctl reload postgresql > /dev/null
endscript
}
这套配置在我们去年的等保测评中获得了满分通过。