利用 Patroni + etcd + HAProxy 搭建高可用 PostgreSQL 集群

在生产环境中,数据库的高可用性是系统稳定运行的关键。本文将详细讲解如何利用 Docker 部署一个由 etcd、Patroni 和 HAProxy 组成的 PostgreSQL 高可用集群,实现自动故障转移和负载均衡。

架构概述

本架构主要包括三部分:

  1. etcd 集群

    etcd 作为分布式键值存储,为 Patroni 提供集群状态、元数据存储与服务发现功能。本例中,我们使用 3 个 etcd 节点构建一个高可用的 etcd 集群。

  2. Patroni 管理的 PostgreSQL 集群

    Patroni 通过监控 PostgreSQL 实例的状态,并利用 etcd 作为一致性存储,实现主从切换与故障恢复。这里我们部署 3 个 Patroni 节点,每个节点内嵌一个 PostgreSQL 实例。

  3. HAProxy 负载均衡器

    HAProxy 作为数据库访问入口,将外部请求均衡分发到 Patroni 管理的 PostgreSQL 实例中。通过健康检查确保只将请求转发到正常的节点上。

Docker 部署示例

下面提供一个完整的 Docker Compose 文件示例,包含 3 个 etcd 节点、3 个 Patroni 节点和 1 个 HAProxy 节点。你只需将以下内容保存为 docker-compose.yaml 文件,并在同级目录下创建 HAProxy 配置文件 haproxy.cfg

docker-compose.yaml

yaml 复制代码
version: "3.9"

services:
  # etcd 集群(三个节点)
  etcd1:
    image: quay.io/coreos/etcd:v3.5.7
    container_name: etcd1
    environment:
      - ETCD_NAME=etcd1
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
    ports:
      - "2379:2379"
      - "2380:2380"
    networks:
      - pat_network

  etcd2:
    image: quay.io/coreos/etcd:v3.5.7
    container_name: etcd2
    environment:
      - ETCD_NAME=etcd2
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
    networks:
      - pat_network

  etcd3:
    image: quay.io/coreos/etcd:v3.5.7
    container_name: etcd3
    environment:
      - ETCD_NAME=etcd3
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
    networks:
      - pat_network

  # Patroni 管理的 PostgreSQL 集群(3 节点)
  patroni1:
    image: zalando/patroni:latest
    container_name: patroni1
    environment:
      - PATRONI_NAME=patroni1
      - PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
      - PATRONI_RESTAPI_CONNECT_ADDRESS=patroni1:8008
      - PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
      - PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni1:5432
      - PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
      - PATRONI_SCOPE=batman_cluster
      - PATRONI_NAMESPACE=/service/
      - PATRONI_LOG_LEVEL=INFO
    volumes:
      - ./patroni1/data:/var/lib/postgresql/data
    ports:
      - "5433:5432"
    depends_on:
      - etcd1
      - etcd2
      - etcd3
    networks:
      - pat_network

  patroni2:
    image: zalando/patroni:latest
    container_name: patroni2
    environment:
      - PATRONI_NAME=patroni2
      - PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
      - PATRONI_RESTAPI_CONNECT_ADDRESS=patroni2:8008
      - PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
      - PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni2:5432
      - PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
      - PATRONI_SCOPE=batman_cluster
      - PATRONI_NAMESPACE=/service/
      - PATRONI_LOG_LEVEL=INFO
    volumes:
      - ./patroni2/data:/var/lib/postgresql/data
    ports:
      - "5434:5432"
    depends_on:
      - etcd1
      - etcd2
      - etcd3
    networks:
      - pat_network

  patroni3:
    image: zalando/patroni:latest
    container_name: patroni3
    environment:
      - PATRONI_NAME=patroni3
      - PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
      - PATRONI_RESTAPI_CONNECT_ADDRESS=patroni3:8008
      - PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
      - PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni3:5432
      - PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
      - PATRONI_SCOPE=batman_cluster
      - PATRONI_NAMESPACE=/service/
      - PATRONI_LOG_LEVEL=INFO
    volumes:
      - ./patroni3/data:/var/lib/postgresql/data
    ports:
      - "5435:5432"
    depends_on:
      - etcd1
      - etcd2
      - etcd3
    networks:
      - pat_network

  # HAProxy 作为 PostgreSQL 的访问入口
  haproxy:
    image: haproxy:latest
    container_name: haproxy
    ports:
      - "5432:5432"
    configs:
      - source: haproxy_cfg
        target: /usr/local/etc/haproxy/haproxy.cfg
    depends_on:
      - patroni1
      - patroni2
      - patroni3
    networks:
      - pat_network

configs:
  haproxy_cfg:
    file: ./haproxy.cfg

networks:
  pat_network:
    driver: bridge

haproxy.cfg

在与 docker-compose.yaml 同级目录下创建 haproxy.cfg 文件,内容如下:

cfg 复制代码
global
    log stdout format raw local0

defaults
    log     global
    mode    tcp
    timeout connect 10s
    timeout client  30s
    timeout server  30s

frontend pgsql_front
    bind *:5432
    default_backend pgsql_back

backend pgsql_back
    balance roundrobin
    server patroni1 patroni1:5432 check port 8008
    server patroni2 patroni2:5432 check port 8008
    server patroni3 patroni3:5432 check port 8008

部署步骤

  1. 准备环境

    将上述两个文件(docker-compose.yamlhaproxy.cfg)放置在同一目录中,同时为每个 Patroni 节点创建对应的数据目录(例如:./patroni1/data./patroni2/data./patroni3/data)。

  2. 启动服务

    在目录中执行以下命令启动所有服务:

    bash 复制代码
    docker-compose up -d
  3. 验证部署

    • 通过 docker ps 检查所有容器均已正常启动。
    • 通过访问 HAProxy 映射的端口(5432),即可连接到后端 Patroni 集群中的 PostgreSQL 实例。
    • 通过 Patroni 的 REST API 端口(各容器的 8008 端口)可查询集群状态与节点信息。

总结

使用 Patroni + etcd + HAProxy 构建的 PostgreSQL 高可用集群能够实现自动故障转移和负载均衡,确保数据库服务在节点故障时依然保持可用。该方案适用于需要高可用数据库支撑的生产环境。

通过 Docker Compose 快速构建此架构后,后续可以结合 Kubernetes 等编排工具进一步扩展部署,实现更高的弹性与可维护性。

希望这篇博客对你在高可用数据库部署方面有所帮助,如有疑问或进一步需求,欢迎在评论区交流!

相关推荐
try2find1 小时前
llama-webui docker实现界面部署
docker·容器·llama
知远同学1 小时前
docker学习笔记2-最佳实践
运维·docker·容器
Paraverse_徐志斌2 小时前
MySQL 线上大表 DDL 如何避免锁表(pt-online-schema-change)
数据库·mysql·ddl·mysql锁·锁表·pt-osc
哈哈幸运2 小时前
MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境
linux·运维·数据库·mysql·性能优化
愚公搬代码2 小时前
【愚公系列】《Python网络爬虫从入门到精通》055-Scrapy_Redis分布式爬虫(安装Redis数据库)
数据库·爬虫·python
pwzs3 小时前
深入浅出 MVCC:MySQL 并发背后的多版本世界
数据库·后端·mysql
大熊猫今天吃什么3 小时前
【一天一坑】空数组,使用 allMatch 默认返回true
前端·数据库
双叶8363 小时前
(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)
c语言·数据库·单片机·嵌入式硬件·mongodb·51单片机·nosql
XY.散人3 小时前
初识Redis · C++客户端list和hash
数据库·redis·缓存
Java后端何哥4 小时前
Docker Compose 和 Kubernetes(k8s)区别
docker·容器·kubernetes