一、当你的数据库需要"瘦身":流复制缩容的必要场景

我们的数据库集群就像一支不断扩张的乐队,随着业务发展不断加入新乐手(从库节点)。但当演奏场景从大型音乐会换成小剧场时,这些冗余的乐手反而会影响整体配合。最常见的三种缩容需求场景:

  1. 资源过剩型瘦身
    某电商平台大促后,原本支撑高并发的5节点集群需要回归日常运营状态。此时可保留3节点保障基础可用性,将两个从库节点资源释放给其他业务

  2. 架构优化型调整
    某社交平台将原来的多地双活架构调整为单元化部署,需要下线异地灾备节点。这时需确保下线节点不会影响本地集群运行

  3. 问题节点退役
    当某个从库节点出现硬件故障或性能瓶颈时,直接将其移出复制集群比维修更高效。曾有DBA遇到RAID卡故障的物理机,通过缩容操作在15分钟内完成故障隔离

# 示例:查看当前复制集群状态(PostgreSQL 14)
psql -h primary_node -U replicator -c "
SELECT client_addr AS 节点IP, 
       state AS 状态,
       write_lag + flush_lag + replay_lag AS 总延迟,
       pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn)) AS 未应用数据量
FROM pg_stat_replication;"

# 输出示例:
#   节点IP   |   状态   | 总延迟 | 未应用数据量 
#-------------+---------+--------+--------------
# 192.168.1.2 | streaming | 2.1s   | 128 MB
# 192.168.1.3 | streaming | 15.4s  | 2.1 GB  <-- 需移除的异常节点

二、安全下线

1. 术前检查不可少

如同外科医生术前要确认患者体征,DBA需要确认以下关键指标:

  • 目标节点复制延迟不超过5秒
  • 主库未处于基础备份状态
  • 所有业务读写都配置了重试机制
  • 维护窗口时间足够完成操作
-- 预检完整脚本(主库执行)
DO $$
DECLARE
    repl_status RECORD;
BEGIN
    -- 检测是否处于备份状态
    IF EXISTS (SELECT 1 FROM pg_stat_activity WHERE query LIKE 'pg_basebackup%') THEN
        RAISE EXCEPTION '存在正在运行的基础备份';
    END IF;

    -- 检测所有从库状态
    FOR repl_status IN 
        SELECT client_addr, state, pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes
        FROM pg_stat_replication
    LOOP
        IF repl_status.lag_bytes > 500000000 THEN  -- 超过500MB视为异常
            RAISE NOTICE '节点 % 存在 %.2f MB的延迟', 
                repl_status.client_addr, 
                repl_status.lag_bytes::numeric/1048576;
        END IF;
    END LOOP;
END $$;

2. 优雅停复制的正确姿势

突然中断复制就像急刹车,可能造成数据碎片。正确操作应该是:

# 在待移除的从库节点执行
pg_ctl pause    # 暂停数据接收(PostgreSQL 14新特性)
pg_ctl stop -m smart  # 优雅关闭实例

# 主库上释放复制槽(防止WAL堆积)
psql -h primary_node -c "
SELECT pg_drop_replication_slot(slot_name) 
FROM pg_replication_slots 
WHERE active_pid IS NULL;"

3. 配置文件的蝴蝶效应

修改主库的pg_hba.conf时,老DBA容易踩的坑:

  • 禁用IP段而非精确IP导致误杀
  • 忘记reload配置直接重启
  • 未保留变更记录
# 安全修改示例
TIMESTAMP=$(date +%Y%m%d%H%M)
cp /var/lib/pgsql/14/data/pg_hba.conf /backup/pg_hba.conf.$TIMESTAMP

# 使用精确锁定(建议通过配置管理工具执行)
sed -i "/^host replication replicator 192.168.1.3\/32/d" /var/lib/pgsql/14/data/pg_hba.conf

# 优雅加载配置
psql -h localhost -U postgres -c "SELECT pg_reload_conf()"

三、防踩坑指南:血泪经验总结

1. 幽灵复制槽的诅咒

某次缩容操作后三天,主库突然出现磁盘告警。追查发现遗留的复制槽仍在持续堆积WAL日志。这要求我们必须:

-- 缩容后的主库检查脚本
WITH dead_slots AS (
    SELECT slot_name, 
           pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as retained_size
    FROM pg_replication_slots 
    WHERE active = false
)
SELECT * FROM dead_slots WHERE retained_size > '1GB';

2. 负载均衡器的无声背叛

下架节点后,运维人员经常忘记同步调整HAProxy或Nginx配置。推荐采用自动化联动:

# Ansible剧本示例(片段)
- name: 更新负载均衡配置
  hosts: load_balancer
  tasks:
    - name: 从后端池移除节点
      lineinfile:
        path: /etc/haproxy/haproxy.cfg
        regexp: 'server pg-node3 '
        state: absent
      notify: reload haproxy

  handlers:
    - name: reload haproxy
      systemd:
        name: haproxy
        state: reloaded

四、延伸战场:故障节点的重生之术

对于可能需要重新加入集群的节点,聪明的DBA会先做pg_rewind:

# 数据分歧修复示例
pg_ctl stop
rm -rf /var/lib/pgsql/14/data/*
pg_basebackup -h primary_node -U replicator -D /var/lib/pgsql/14/data -X stream
pg_ctl start

五、技术选型的双面性

流复制缩容的优点

  • 毫米级精度:基于WAL日志的同步机制
  • 热操作可能性:部分场景可在线完成
  • 生态完整:丰富的监控工具链

需要警惕的短板

  • 级联复制拓扑中可能引发连锁反应
  • 大事务处理时需要更高超的平衡技巧
  • 对网络抖动的容错性较云原生方案弱

六、写给未来的自己:最佳实践备忘录

  1. 变更三板斧:操作前拍快照、操作中做记录、操作后留监控
  2. 熔断机制:在下线过程中预设可快速回滚的锚点
  3. 业务视角验证:不只是数据库状态正常,更要确认应用日志无异常
  4. 容量规划:缩容后的集群剩余资源应有30%安全余量