一、背景说明
生产环境中,PostgreSQL 的归档配置如下:
archive_command = 'rsync -a %p postgres@10.1.1.2:/var/lib/pgsql/archive/%f'
关键特征:
-
使用 postgres 用户
-
通过 rsync + ssh
-
每个 WAL 段一次独立连接
-
无交互(必须免密)
为了复现并分析 rsync/ssh 在该模型下的性能上限,我在两台新服务器上搭建了等价环境:
| 角色 | IP | 说明 |
|---|---|---|
| A(发送端) | 192.168.1.167 | 模拟主库,执行 archive_command |
| B(接收端) | 192.168.1.240 | 模拟归档机 |
| Jumpserver | -- | 仅用于人工登录,不参与运行时链路 |
⚠️ 注意:
archive_command 运行时是 A → B 直连 ,不会经过 jumpserver,jumpserver 仅用于"人工运维操作"。
二、目标
实现:
A 上的 postgres 用户
→ 通过 SSH 免密
→ 直连 B 上的 postgres 用户
→ 执行 rsync
三、免密登录配置步骤
1️⃣ A 上生成 postgres 用户的 SSH key
sudo -u postgres -i
echo $HOME
# /var/lib/pgsql
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_ed25519
生成:
-
/var/lib/pgsql/.ssh/id_ed25519
-
/var/lib/pgsql/.ssh/id_ed25519.pub
2️⃣ 通过 jumpserver 登录到 B,注入公钥
由于 B 无密码、只能通过 jumpserver 登录,无法使用 ssh-copy-id,只能手工注入。
在 B 上:
sudo -u postgres -i
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat >> ~/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAAC3... postgres@ip-192-168-1-167
EOF
chmod 600 ~/.ssh/authorized_keys
exit
3️⃣ 修复 SELinux 上下文(非常关键)
B 上执行:
restorecon -Rv /var/lib/pgsql/.ssh
输出示例:
Relabeled /var/lib/pgsql/.ssh to ssh_home_t
Relabeled /var/lib/pgsql/.ssh/authorized_keys to ssh_home_t
如果跳过这一步,在 SELinux Enforcing 的系统上,免密会"看起来都对但就是不生效"。
四、问题出现:A 连接 B 卡住
在 A 上验证免密:
sudo -u postgres ssh -o BatchMode=yes postgres@192.168.1.240 "echo OK"
现象:
-
命令卡住,无输出
-
不报权限错误
-
不提示密码
五、排查过程(关键)
1️⃣ 使用 ssh 调试模式定位阶段
sudo -u postgres ssh -vvv postgres@192.168.1.240
输出停留在:
debug1: Connecting to 192.168.1.240 [192.168.1.240] port 22.
👉 说明:连接卡在 TCP 层,尚未进入 SSH 协议
2️⃣ 验证端口连通性
nc -vz 192.168.1.240 22
结果:连接失败
3️⃣ 结论定位
-
jumpserver 能连 B
-
A → B 22 端口不通
-
SSH 尚未进入认证阶段
👉 根因:安全组 / 防火墙未放通 A → B 的 22 端口
4️⃣ 修复
在云平台安全组中:
- 放通 192.168.1.167 → 192.168.1.240:22
六、修复后验证
再次在 A 上执行:
sudo -u postgres ssh -o BatchMode=yes postgres@192.168.1.240 "echo OK"
输出:
OK
免密登录成功 🎉
八、Checklist(30 秒自检版)
-
A → B 的 22 端口是否放通
-
postgres home 权限是否 700
-
authorized_keys 权限是否 600
-
SELinux context 是否为 ssh_home_t
-
postgres 是否允许 ssh 登录