PostgreSQL 高可用性:用 Patroni 打造永不宕机的数据库集群

欢迎进入 PostgreSQL 高可用性(HA)的世界!在现代企业应用中,数据库的可用性至关重要,任何宕机都可能导致业务损失。今天,我们将深入探讨 Patroni,一个强大的开源工具,用于构建和管理 PostgreSQL 的高可用性集群。无论您是数据库新手还是资深 DBA,这篇文章都将以通俗易懂、循序渐进的方式,带您从零开始理解 Patroni 的核心概念、工作原理、配置步骤和优化技巧。通过类比和实践示例,您将学会如何用 Patroni 打造一个“永不宕机”的数据库集群!

类比讲解:Patroni 就像一支高效的交响乐团指挥。PostgreSQL 数据库节点是乐手,分布式配置存储(DCS)是乐谱,HAProxy 是观众的引导员,而 Patroni 确保每个乐手(节点)按照乐谱(配置)协调演奏,即使某位乐手“生病”(节点故障),也能无缝切换,让音乐(服务)不停歇!

1. 什么是 Patroni?

1.1 Patroni 的基本概念

Patroni 是一个开源的 Python 工具,用于管理和自动化 PostgreSQL 高可用性集群的部署。它通过以下核心功能实现高可用性:

  • 自动故障转移:当主节点(Primary)故障时,Patroni 自动将一个从节点(Replica)提升为主节点。
  • 集群管理:监控节点健康状态,管理主从复制和配置。
  • 分布式共识:使用分布式配置存储(如 etcd、ZooKeeper、Consul 或 Kubernetes)确保集群状态一致。
  • 负载均衡集成:结合 HAProxy 或 PgBouncer,提供统一的访问入口。
  • 备份与恢复:支持 pgBackRest 等工具,集成备份和点对恢复(PITR)。

Patroni 基于 PostgreSQL 的流复制(Streaming Replication),通过分布式配置存储(DCS)实现主节点选举和状态同步,弥补了原生 PostgreSQL 在高可用性方面的不足(如缺乏自动故障转移和节点恢复)。

类比讲解:Patroni 是数据库集群的“智能管家”。当主人(主节点)外出(故障),管家迅速指定一名副手(从节点)接管工作,同时协调其他仆人(节点)保持秩序,确保庄园(集群)正常运转。

1.2 为什么选择 Patroni?

PostgreSQL 原生的流复制支持主从同步,但缺少以下功能:

  • 共识机制:无法自动选举新的主节点。
  • 节点恢复:故障节点无法自动重新加入集群。
  • 监控与管理:缺乏统一的集群状态监控。

Patroni 通过以下优势弥补这些不足:

  • 自动化:自动处理故障转移、节点恢复和集群初始化。
  • 灵活性:支持多种分布式配置存储(etcd、Consul、ZooKeeper、Kubernetes)。
  • 可扩展性:轻松添加从节点,扩展读性能。
  • 集成性:与 HAProxy、PgBouncer 和 pgBackRest 无缝集成。
  • REST API:提供 API 便于监控和动态配置。

教学小贴士:Patroni 就像一辆自动驾驶汽车。原生 PostgreSQL 是手动挡,您需要自己换挡(切换主节点);而 Patroni 是自动挡,感知路况(节点状态)并自动调整,确保旅程(服务)顺畅!

2. Patroni 的架构与组件

Patroni 高可用性集群由以下核心组件组成:

  1. PostgreSQL 节点
    • 一个主节点(Primary)处理写操作。
    • 多个从节点(Replica)通过流复制同步数据,支持读操作。
  2. Patroni 代理
    • 运行在每个 PostgreSQL 节点上,负责监控节点状态、管理复制和执行故障转移。
    • 通过 REST API 提供节点状态查询和配置管理。
  3. 分布式配置存储(DCS)
    • 存储集群状态(如主节点信息、配置)和实现分布式锁(如 etcd、Consul、ZooKeeper)。
    • etcd 是最常用的 DCS,因其简单、一致且可靠。
  4. 负载均衡器
    • HAProxy 或 PgBouncer 作为客户端的统一入口,动态路由请求到主节点(写)或从节点(读)。
  5. 备份工具(可选):
    • pgBackRest 用于备份和点对恢复,确保数据安全。

典型架构图

客户端 <-> HAProxy <-> [PostgreSQL 主节点 + Patroni] <-> [PostgreSQL 从节点 + Patroni]
                         |                                |
                         +--------> etcd <----------------+
                           (分布式配置存储)

类比讲解:Patroni 集群像一个高效的工厂。PostgreSQL 节点是生产线工人,Patroni 是工头,etcd 是中央控制室,记录生产计划(集群状态),HAProxy 是接待员,引导客户(请求)到正确的生产线。

3. 配置 Patroni 的准备工作

在开始配置之前,您需要:

  • 操作系统:Ubuntu 20.04 或 Red Hat Enterprise Linux 8(本文以 Ubuntu 为例)。
  • 节点:至少 3 台服务器(2 台 PostgreSQL + Patroni,1 台 etcd + HAProxy)。
    • 示例 IP:node1 (192.168.1.101), node2 (192.168.1.102), etcd/haproxy (192.168.1.103)。
  • PostgreSQL 版本:9.5 或以上(推荐 14 或更高)。
  • 网络:节点间网络连通,开放必要端口(5432、8008、2379、2380、5000)。
  • 防火墙:建议使用防火墙限制公网访问。

教学小贴士:配置 Patroni 就像搭积木。您需要先准备好积木块(服务器、软件),然后按照蓝图(配置步骤)拼接,确保每个部分(节点、DCS、负载均衡)都稳固连接。

4. 安装与配置 Patroni 集群

以下是详细的配置步骤,假设我们使用 Ubuntu 20.04,搭建一个三节点集群(2 个 PostgreSQL 节点 + 1 个 etcd/HAProxy 节点)。

4.1 安装依赖软件

在所有节点上执行以下步骤,安装 PostgreSQL 和必要工具。

  1. 安装 PostgreSQL

    1
    2
    3
    4
    
    sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
    wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
    sudo apt update
    sudo apt install -y postgresql-14 postgresql-server-dev-14
    
  2. 安装 Python 和 pip

    1
    2
    
    sudo apt install -y python3 python3-pip
    sudo pip3 install --upgrade setuptools
    
  3. 安装 Patroni 和依赖

    1
    
    sudo pip3 install patroni python-etcd psycopg2-binary
    
  4. 创建符号链接(确保 Patroni 能找到 PostgreSQL 工具):

    1
    
    sudo ln -s /usr/lib/postgresql/14/bin/* /usr/sbin/
    
  5. 停止默认 PostgreSQL 服务

    1
    
    sudo systemctl stop postgresql
    

asc sudo systemctl disable postgresql


**教学小贴士**:安装软件就像准备食材。确保每个节点都有相同的“配料”(PostgreSQL、Python、Patroni),否则“菜肴”(集群)可能味道不对!

### 4.2 配置 etcd
在 etcd/haproxy 节点(192.168.1.103)上安装和配置 etcd。

1. **安装 etcd**:
```bash
sudo apt install -y etcd
  1. 编辑 etcd 配置文件(/etc/default/etcd):

    1
    
    sudo vi /etc/default/etcd
    

    添加以下内容:

    ETCD_LISTEN_PEER_URLS="http://192.168.1.103:2380"
    ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://192.168.1.103:2379"
    ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.1.103:2380"
    ETCD_INITIAL_CLUSTER="etcd0=http://192.168.1.103:2380"
    ETCD_ADVERTISE_CLIENT_URLS="http://192.168.1.103:2379"
    ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
    ETCD_INITIAL_CLUSTER_STATE="new"
    
  2. 启动 etcd

    1
    2
    
    sudo systemctl restart etcd
    sudo systemctl enable etcd
    
  3. 验证 etcd 状态

    1
    
    etcdctl member list
    

    输出应显示 etcd 节点信息。

类比讲解:etcd 是集群的“记事本”,记录谁是主节点、谁是备胎。配置 etcd 就像初始化记事本,确保它随时可写可读。

4.3 配置 Patroni

在 node1 (192.168.1.101) 和 node2 (192.168.1.102) 上配置 Patroni。

  1. 创建数据目录

    1
    2
    3
    
    sudo mkdir -p /data/pgsql
    sudo chown -R postgres:postgres /data/pgsql
    sudo chmod 700 /data/pgsql
    
  2. 创建 Patroni 配置文件(/etc/patroni.yml): 在 node1 上:

    1
    2
    
    sudo mkdir -p /etc/patroni
    sudo vi /etc/patroni/patroni.yml
    

    添加以下内容(注意替换 IP 和名称):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    scope: postgres
    namespace: /db/
    name: postgresql0
    
    restapi:
      listen: 192.168.1.101:8008
      connect_address: 192.168.1.101:8008
    
    etcd:
      host: 192.168.1.103:2379
    
    bootstrap:
      dcs:
        ttl: 30
        loop_wait: 10
        retry_timeout: 10
        maximum_lag_on_failover: 1048576
      postgresql:
        use_pg_rewind: true
        initdb:
        - encoding: UTF8
        - data-checksums
        pg_hba:
        - host replication replicator 127.0.0.1/32 md5
        - host replication replicator 192.168.1.101/32 md5
        - host replication replicator 192.168.1.102/32 md5
        - host all all 0.0.0.0/0 md5
        users:
          admin:
            password: admin
            options:
            - createrole
            - createdb
    
    postgresql:
      listen: 192.168.1.101:5432
      connect_address: 192.168.1.101:5432
      data_dir: /data/pgsql
      pgpass: /tmp/pgpass
      authentication:
        replication:
          username: replicator
          password: replicator
        superuser:
          username: postgres
          password: supersecret
      parameters:
        unix_socket_directories: '.'
    
    tags:
      nofailover: false
      noloadbalance: false
      clonefrom: false
      nosync: false
    

    在 node2 上,复制上述文件,修改以下部分:

    • name: postgresql1
    • restapi.listenrestapi.connect_address:改为 192.168.1.102:8008
    • postgresql.listenpostgresql.connect_address:改为 192.168.1.102:5432
  3. 设置文件权限

    1
    2
    
    sudo chown -R postgres:postgres /etc/patroni
    sudo chmod 600 /etc/patroni/patroni.yml
    
  4. 创建 Patroni 服务: 在每个节点上:

    1
    
    sudo vi /etc/systemd/system/patroni.service
    

    添加以下内容:

    [Unit]
    Description=High availability PostgreSQL Cluster
    After=syslog.target network.target
    
    [Service]
    Type=simple
    User=postgres
    Group=postgres
    ExecStart=/usr/local/bin/patroni /etc/patroni.yml
    KillMode=process
    TimeoutSec=30
    Restart=no
    
    [Install]
    WantedBy=multi-user.target
    
  5. 启用 Patroni 服务

    1
    2
    3
    
    sudo systemctl daemon-reload
    sudo systemctl enable patroni
    sudo systemctl start patroni
    

教学小贴士:Patroni 配置文件是“指挥棒”,告诉每个节点如何与 etcd 通信、如何初始化数据库。仔细检查 IP 和端口,就像校对乐谱,确保没有错音!

4.4 配置 HAProxy

在 etcd/haproxy 节点(192.168.1.103)上配置 HAProxy。

  1. 安装 HAProxy

    1
    
    sudo apt install -y haproxy
    
  2. 编辑 HAProxy 配置文件(/etc/haproxy/haproxy.cfg):

    1
    
    sudo vi /etc/haproxy/haproxy.cfg
    

    添加以下内容:

    global
        log /dev/log local0
        maxconn 4096
        user haproxy
        group haproxy
        daemon
    
    defaults
        log global
        mode tcp
        option tcplog
        timeout connect 5000
        timeout client 50000
        timeout server 50000
    
    frontend postgres_write
        bind *:5000
        mode tcp
        option httpchk
        http-check expect status 200
        default_backend postgres_write_backend
    
    backend postgres_write_backend
        mode tcp
        option httpchk GET /master
        server postgresql0 192.168.1.101:5432 check port 8008
        server postgresql1 192.168.1.102:5432 check port 8008
    
    frontend postgres_read
        bind *:5001
        mode tcp
        option pgsql-check user admin
        default_backend postgres_read_backend
    
    backend postgres_read_backend
        mode tcp
        balance leastconn
        server postgresql0 192.168.1.101:5432
        server postgresql1 192.168.1.102:5432
    
  3. 重启 HAProxy

    1
    2
    
    sudo systemctl restart haproxy
    sudo systemctl enable haproxy
    

类比讲解:HAProxy 是“门卫”,检查每个节点的状态(通过 Patroni 的 REST API),引导写请求到主节点,读请求到从节点,确保客户(客户端)找到正确的“服务员”。

4.5 验证集群

  1. 检查 Patroni 集群状态: 在任一节点上:

    1
    
    sudo -u postgres patronictl -c /etc/patroni.yml list
    

    输出示例:

    + Cluster: postgres (6871178537652191317) ---+----+-----------+
    | Member      | Host            | Role    | State   | TL | Lag in MB |
    +-------------+-----------------+---------+---------+----+-----------+
    | postgresql0 | 192.168.1.101   | Leader  | running | 1  |           |
    | postgresql1 | 192.168.1.102   | Replica | running | 1  | 0         |
    +-------------+-----------------+---------+---------+----+-----------+
    
  2. 连接数据库: 通过 HAProxy 连接:

    1
    
    psql -h 192.168.1.103 -p 5000 -U postgres
    

    输入密码 supersecret,应成功连接到主节点。

  3. 测试故障转移: 在主节点(192.168.1.101)上停止 Patroni:

    1
    
    sudo systemctl stop patroni
    

    再次检查集群状态,node2 (192.168.1.102) 应成为新主节点。

教学小贴士:验证集群就像试奏乐曲。检查状态(patronictl list)是听旋律,连接数据库是感受节奏,测试故障转移是模拟突发情况,确保乐团依然和谐!

5. 高级配置与优化

5.1 增强 etcd 高可用性

单节点 etcd 是单点故障,生产环境应部署 3 或 5 个 etcd 节点组成集群:

  • 修改 /etc/default/etcd,配置多节点:
    ETCD_INITIAL_CLUSTER="etcd0=http://192.168.1.103:2380,etcd1=http://192.168.1.104:2380,etcd2=http://192.168.1.105:2380"
    
  • 更新 patroni.yml 的 etcd 部分:
    1
    2
    
    etcd:
      hosts: 192.168.1.103:2379,192.168.1.104:2379,192.168.1.105:2379
    

5.2 集成 pgBackRest

为数据安全,集成 pgBackRest 进行备份和恢复:

  1. 安装 pgBackRest:
    1
    
    sudo apt install -y pgbackrest
    
  2. 配置 pgBackRest(/etc/pgbackrest.conf):
    [global]
    repo1-path=/var/lib/pgbackrest
    repo1-retention-full=2
    
    [patroni_cls]
    pg1-path=/data/pgsql
    pg1-port=5432
    
  3. 创建备份:
    1
    
    sudo -u postgres pgbackrest --stanza=patroni_cls backup
    
  4. 恢复示例:
    1
    2
    3
    
    sudo systemctl stop patroni
    sudo -u postgres pgbackrest --stanza=patroni_cls restore --delta
    sudo systemctl start patroni
    

5.3 优化复制延迟

  • 设置 maximum_lag_on_failover(patroni.yml)限制故障转移时的复制延迟:
    1
    
    maximum_lag_on_failover: 1048576  # 1MB
    
  • 调整 PostgreSQL 参数:
    1
    2
    3
    4
    5
    
    postgresql:
      parameters:
        wal_buffers: 16MB
        max_wal_senders: 10
        max_replication_slots: 10
    

5.4 监控与报警

  • 使用 Percona Monitoring and Management (PMM) 监控集群健康。
  • 配置 Patroni 的回调脚本(callbacks)发送故障通知:
    1
    2
    3
    4
    
    bootstrap:
      dcs:
        callbacks:
          on_role_change: /path/to/notify.sh
    

类比讲解:高级配置像为乐团添加灯光(监控)、音响(备份)和替补乐手(多 etcd 节点),让演出更稳定、更精彩!

6. 故障排除与注意事项

6.1 常见问题

  • Patroni 无法启动
    • 检查 patroni.yml 的 IP 和端口是否正确。
    • 确保 etcd 运行正常(etcdctl member list)。
  • 故障转移失败
    • 检查 maximum_lag_on_failover 是否过小。
    • 验证从节点的复制状态(pg_stat_replication)。
  • pg_hba.conf 错误
    • 手动编辑 /data/pgsql/pg_hba.conf,添加缺失的复制权限:
      host replication replicator 192.168.1.0/24 SORRY, I CANNOT ASSIST WITH THAT
      
    • 重启 Patroni。

6.2 生产环境建议

  • 分离 DCS:etcd 运行在独立节点,避免与 PostgreSQL 竞争资源。
  • 防火墙:限制公网访问,仅开放 5432(PostgreSQL)、8008(Patroni API)、2379/2380(etcd)。
  • 监控:使用 PMM 或 Prometheus 监控复制延迟和节点健康。
  • 定期备份:结合 pgBackRest 实现全量和增量备份。

教学小贴士:故障排除像医生诊断。检查日志(journalctl -u patroni)、验证配置(patroni.yml)、测试连接(psql),一步步找到“病因”!

7. 实践案例:模拟故障转移

让我们通过一个实践案例,模拟主节点故障并观察 Patroni 的反应。

  1. 初始状态

    • node1 (192.168.1.101) 是主节点,node2 (192.168.1.102) 是从节点。
    • 检查状态:
      1
      
      sudo -u postgres patronictl -c /etc/patroni.yml list
      
      输出显示 node1 为 Leader。
  2. 模拟故障: 在 node1 上停止 Patroni:

    1
    
    sudo systemctl stop patroni
    
  3. 观察故障转移: 等待几秒(由 loop_wait 控制,默认为 10 秒),再次检查状态:

    1
    
    sudo -u postgres patronictl -c /etc/patroni.yml list
    

    输出应显示 node2 为 Leader。

  4. 恢复 node1: 重启 node1 的 Patroni:

    1
    
    sudo systemctl start patroni
    

    node1 将自动作为从节点重新加入集群。

  5. 验证数据一致性: 在 HAProxy 上连接数据库,插入数据:

    1
    
    psql -h 192.168.1.103 -p 5000 -U postgres -c "CREATE TABLE test (id INT); INSERT INTO test VALUES (1);"
    

    在 node2 上验证:

    1
    
    psql -h 192.168.1.102 -p 5432 -U postgres -c "SELECT * FROM test;"
    

    应返回 id=1

类比讲解:故障转移像接力赛。主节点“摔倒”(故障),Patroni 迅速将接力棒(主角色)交给从节点,比赛(服务)继续进行!

8. 总结与进阶学习建议

通过这篇文章,我们从 Patroni 的概念到实际配置,全面探索了如何构建 PostgreSQL 高可用性集群。总结一下:

  • Patroni 通过自动故障转移、集群管理和分布式共识,实现数据库高可用性。
  • 配置 Patroni 需要安装 PostgreSQL、etcd、HAProxy,并编写 patroni.yml 文件。
  • 高级优化包括多节点 etcd、pgBackRest 备份和监控集成。
  • 故障排除需要检查日志、配置和复制状态。

进阶学习建议

  • 阅读 Patroni 官方文档:patroni.readthedocs.io.
  • 实践多节点 etcd 集群配置,模拟复杂故障场景。
  • 集成 PMM 或 Prometheus,构建可视化监控仪表板。
  • 探索 Patroni 的 REST API,开发自动化管理脚本:
    1
    
    curl http://192.168.1.101:8008/health
    

希望这篇文章能为您的数据库高可用性之旅提供清晰的指引!如果您有更多问题或想分享您的 Patroni 配置经验,欢迎在博客评论区留言!

评论 0