PostgreSQL高可用方案-patroni+etcd+vipmanager(一)
1 前言
1.1概述
Patroni + etcd + vipmanager 是cybertec推出的postgresql 高可用方案。其中, Etcd 用于存放集群状态信息。Patroni 负责为PostgreSQL 集群提供故障转移和高可用服务。vipmanager 根据etcd或Consul中保存的状态管理虚拟IP用于提供和管理虚拟ip,用于对外提供访问地址。
1.2 方案架构
1.3 软件介绍
1.3.1 etcd
etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。
etcd作为服务发现系统,有以下的特点:
- 简单:安装配置简单,而且提供了HTTP API进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:根据官方提供的benchmark数据,单实例支持每秒2k+读操作
- 可靠:采用raft算法,实现分布式系统数据的可用性和一致性
1.3.2 Patroni
Patroni是Cybertec公司开发的,可用于使用流复制来创建,管理,维护和监视高可用性PostgreSQL集群设置的工具。
Patroni 是根据MIT许可证发行的,可以通过PIP轻松安装。 对于Ubuntu和Debian,可以通过系统存储库获得;对于Fedora,CentOS或RHEL,CYBERTEC提供了RPM软件包。.
1.3.2 vip-manager
vip-manager是Cybertec公司开发的,根据etcd或Consul中保存的状态管理虚拟IP的工具。如果 vip-manager 看到它在当前主数据库所在服务器上运行,它将获取虚拟IP。
1.4 方案的功能
该方案实现PostgreSQL的高可用和在线恢复。主要的功能如下:
1. 在主数据库所在服务器上,创建接受访问的虚拟IP。若主数据库改变,虚拟ip也会漂移到新主数据库所在的节点。
2. 若主数据库停止,自动启动主数据库;
3. 若后备数据库停止,自动启动后备数据库;
4. 若主数据库无法启动,则将某一后备数据库提升为主数据库,将旧的主数据库降级为后备数据库,之后它可通过一条命令重新初始化;
5. 若后备数据库无法启动,它可通过一条命令重新初始化;
6. 支持手动切换主数据库和后备数据库;
1.5 实验环境
本实验需要两台服务器。
硬件:
内存:32G
CPU:双核四线程CPU * 2
操作系统:
Centos 7.5
软件环境:
yum
Python 3.6.8
pip 9.0.3
etcd 3.3.11
patroni 2.0.2
PostgreSQL 12.4
vip-manager 1.0
主服务器(primary)的ip地址是10.19.134.134,主机名是node134。PostgreSQL 的主节点和patroni 的主节点均在此部署。
后备服务器(standby)的ip地址是10.19.134.135,主机名是node135。PostgreSQL 的备节点和patroni 的备节点均在此部署。
集群对外提供服务的虚拟ip 是 10.19.134.140。
2 安装和部署
2.1 安装和部署etcd
在两台服务器上分别部署etcd 3.3。
安装和部署etcd的方法详见下面的文章:
在Linux上部署etcd集群
2.2 安装PostgreSQL
在两台服务器上分别安装PostgreSQL。本文中,我们通过源码安装 PostgreSQL 12.4。
1. 关闭防火墙。
[root@node134 ~]# systemctl disable --now firewalld
2. 关闭selinex。
[root@node134 ~]# sed -e '/^ \{0,\}SELINUX=/c\SELINUX=disabled' -i /etc/selinux/config
setenforce 0
3. 安装依赖。
[root@node134 ~]# yum -y install readline-devel zlib-devel gcc
[root@node134 ~]# yum -y install perl perl-devel perl-ExtUtils-Embed
[root@node134 ~]# yum -y install python python-devel
4. 创建用户组postgres。
[root@node134 ~]# groupadd postgres
5. 创建用户postgres,并且设置这个用户属于用户组postgres:
[root@node134 ~]# useradd -d /var/lib/pgsql -g postgres postgres
6. 从官网下载PostgreSQL源码,这里我们下载 postgresql-12.4.tar.gz
7. 在数据库所在服务器上解压它。
[root@node134 ~]# tar zxvf postgresql-12.4.tar.gz
8. 进入解压后的目录,并编译和安装PostgreSQL。
[root@node134 ~]# ./configure --prefix=/opt/postgresql-12 --with-perl --with-python
[root@node134 ~]# make world
[root@node134 ~]# make install-world
这里 --prefix=/opt/postgresql-12 表示 PostgreSQL 的安装目录是 “/opt/postgresql-12”。
9. 修改PostgreSQL 的安装目录的拥用者为 postgres,并设置用户权限。
[root@node134 ~]# chown postgres:postgres /opt/postgresql-12/ -R
[root@node134 ~]# chmod 755 /opt/postgresql-12/ -R
10. 切换OS用户为postgres,之后的操作均通过此用户完成。
[root@node134 ~]# su postgres
11. 创建PostgreSQL的数据目录。
[postgres@node134 ~]# /opt/postgresql-12/bin/initdb -U postgres -D /opt/postgresql-12/data -E utf8
12. 根据需要,修改 postgresql.conf 中的参数。
比如:
listen_addresses = '*'
logging_collector = on
log_directory = 'pg_log'
13. 启动数据库。
[postgres@node134 ~]# cd /opt/postgresql-12/bin
[postgres@node134 ~]# ./pg_ctl start -D ../data
14. 登录数据库,修改postgres用户的密码。
[postgres@node134 ~]# ./psql -h 127.0.0.1 -U postgres -p 5432
postgres=# alter user postgres password 'postgres123';
postgres=# \q
15. 修改 /data/pg_hba.conf,将认证方式从默认的trust 改为 md5,设置允许访问的ip地址。本实验中,修改和新增的内容如下:
host all all 127.0.0.1/32 md5
host all all 10.19.134.0/24 md5
16. 重启数据库。
[postgres@node134 ~]# cd /opt/postgresql-12/bin
[postgres@node134 ~]# ./pg_ctl restart -D ../data
即完成PostgreSQL 的部署。
2.3 搭建 postgresql 主备集群
部署postgresql 主备集群的方法详见如下文档:
【转载】Linux下PostgreSQL主备环境搭建和切换
2.4 安装和部署Patroni
1. 在两台服务器上安装 epel 源,gcc和python 3:
[root@node134 ~]# yum -y install epel-release
[root@node134 ~]# yum -y install gcc
[root@node134 ~]# yum -y install python3
[root@node134 ~]# yum -y install python3-devel
2. 使用pip安装 psycopg2 和patroni
[root@node134 ~]# pip install psycopg2-binary -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com
[root@node134 ~]# pip install patroni[etcd,consul] -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com
3. 验证是否安装成功:
[root@node134 ~]# which patroni
4. 在主机node134 上创建patroni的配置文件:
[root@node134 ~]# mkdir -p /etc/patroni/
[root@node134 ~]# cd /etc/patroni/
[root@node134 ~]# vi /etc/patroni/patroni_postgresql.yml
内容如下:
scope: postgresql12 namespace: /postgresql/ name: node134 restapi: listen: 10.19.134.134:8008 connect_address: 10.19.134.134:8008 etcd: host: 10.19.134.134:2379 bootstrap: # this section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster # and all other cluster members will use it as a `global configuration` dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 master_start_timeout: 300 synchronous_mode: false postgresql: use_pg_rewind: true use_slots: true parameters: listen_addresses: "*" port: 5432 wal_level: replica hot_standby: "on" wal_keep_segments: 10 max_wal_senders: 10 max_replication_slots: 10 wal_log_hints: "on" postgresql: listen: 10.19.134.0:5432 connect_address: 10.19.134.134:5432 data_dir: /opt/postgresql-12/data bin_dir: /opt/postgresql-12/bin config_dir: /opt/postgresql-12/data pgpass: /etc/patroni/.pgpass authentication: replication: username: repuser password: repuser123 superuser: username: postgres password: postgres123 rewind: username: postgres password: postgres123 tags: nofailover: false noloadbalance: false clonefrom: false nosync: false
5. 修改它的属主为postgres,并设置只有属主才有读写权限,其他用户无任何权限:
[root@node134 ~]# chown -R postgres.postgres /etc/patroni/
[root@node134 ~]# chmod 600 /etc/patroni/patroni_postgresql.yml
6. 在主机node135 上创建patroni的配置文件:
[root@node135 ~]# mkdir -p /etc/patroni/
[root@node135 ~]# cd /etc/patroni/
[root@node135 ~]# vi /etc/patroni/patroni_postgresql.yml
内容如下:
scope: postgresql12 namespace: /postgresql/ name: node135 restapi: listen: 10.19.134.135:8008 connect_address: 10.19.134.135:8008 etcd: host: 10.19.134.135:2379 bootstrap: # this section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster # and all other cluster members will use it as a `global configuration` dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 master_start_timeout: 300 synchronous_mode: false postgresql: use_pg_rewind: true use_slots: true parameters: listen_addresses: "*" port: 5432 wal_level: replica hot_standby: "on" wal_keep_segments: 10 max_wal_senders: 10 max_replication_slots: 10 wal_log_hints: "on" postgresql: listen: 10.19.134.0:5432 connect_address: 10.19.134.135:5432 data_dir: /opt/postgresql-12/data bin_dir: /opt/postgresql-12/bin config_dir: /opt/postgresql-12/data pgpass: /etc/patroni/.pgpass authentication: replication: username: repuser password: repuser123 superuser: username: postgres password: postgres123 rewind: username: postgres assword: postgres123 tags: nofailover: false noloadbalance: false clonefrom: false nosync: false
7. 然后修改它的属主为postgres,并设置只有属主才有读写权限。
[root@node135 ~]# chown -R postgres.postgres /etc/patroni/
[root@node135 ~]# chmod 600 /etc/patroni/patroni_postgresql.yml
8. 我们可以将 patroni 注册为服务。创建文件 /usr/lib/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/patroni_postgresql.yml KillMode=process TimeoutSec=30 Restart=no [Install] WantedBy=multi-user.target
9. 完成后,通过操作系统命令启动和关闭patroni服务:
[root@node134 ~]# systemctl start patroni
10. 在另一个窗口中,查看 patroni 集群状态
[root@node134 ~]# patronictl -c /etc/patroni/patroni_postgresql.yml list
结果如下:
+ Cluster: postgresql12 (6914170278151575561) -----+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+--------------------+---------+---------+----+-----------+ | node134 | 10.19.134.134:5435 | Leader | running | 25 | | | node135 | 10.19.134.135:5435 | Replica | running | 25 | 0 |
从上述信息可知,位于 node134 上的PostgreSQL 是主数据库,位于node135 的是后备数据库。
2.5 安装 vip-manager
1. 安装golang
yum -y install golang
2. 设置环境变量GOPROXY,它表示代理服务,仅在中国大陆需要。
export GOPROXY=https://goproxy.io
3. 下载 vip-manager 源码。本文使用的版本是1.0.1。
4. 解压vip-manager 的源码。
tar zxvf vip-manager-1.0.1.tar.gz
5. 进入解压后的目录vip-manager-1.0.1,编译vip-manager
cd vip-manager-1.0.1
make
6. 将生成的vip-manager二进制文件复制到/usr/bin/vip-manager
cp ./vip-manager /usr/bin/vip-manager
7. 将服务文件从 package/scripts/vip-manager.service 复制到 /usr/lib/systemd/system/
cp ./package/scripts/vip-manager.service /usr/lib/systemd/system/
8. 将安装配置文件从vipconfig/vip-manager.yml 复制到 /etc/default/
cp ./vipconfig/vip-manager.yml /etc/default/
8. 编辑配置文件 /etc/default/vip-manager.yml,修改下面这些参数的值:
ip 要管理的虚拟IP地址
netmask 与虚拟IP vip所属的子网相关联的子网掩码。
interface 运行vip-manager的机器上的本地网络接口。当使用hosting-type=basic(默认)时需要。该界面将添加和删除vip。
trigger-key 将由vip经理监控的DCS中的密钥。必须匹配Patroni配置中的<namespace>/<scope>/leader。当DCS返回的值等于trigger-value时,vip-manager将确保虚拟IP已注册到这台机器。如果不匹配,vip-manager会确保虚拟IP没有注册到这台机器上。
trigger-value DCS的触发键应答将被匹配的值。必须匹配Patroni配置中的<name>。这通常设置为与这个vip-manager实例相关联的patroni集群成员的名称。默认为机器的主机名。
hosting-type 要么是basic要么是hetzner。介绍了虚拟IP的管理机制。默认为basic。
dcs-type vip-manager用于监控触发键的DCS类型。默认为etcd。
dcs-endpoints 定义到达DCS地址的url。可以使用逗号分隔的列表将多个端点传递给这个参数或环境变量。在配置文件中,可以指定一个列表,示例请参见配置示例。dcs-type=etcd时,默认为http://127.0.0.1:2379; dcs-type=consul时,默认为http://127.0.0.1:8500。
同时,用“#”注释掉 etcd-ca-file, etcd-cert-file, etcd-key-file。我们不使用SSL 认证.
9. 在主节点上,这些参数配置如下:
ip: 10.19.134.140 netmask: 24 interface: eth0 trigger-key: "/postgresql/postgresql12/leader" trigger-value: "node134" hosting-type: basic dcs-type: etcd dcs-endpoints: - http://127.0.0.1:2379 - http://10.19.134.134:2379
在备节点上,这些参数配置如下:
ip: 10.19.134.140 netmask: 24 interface: eth0 trigger-key: "/postgresql/postgresql12/leader" trigger-value: "node135" hosting-type: basic dcs-type: etcd dcs-endpoints: - http://127.0.0.1:2379 - http://10.19.134.135:2379
10. 分别在主节点和后备节点上启动vip-manager
systemctl start vip-manager
前言
1.1 etcd简介
etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。
etcd作为服务发现系统,有以下的特点:
- 简单:安装配置简单,而且提供了HTTP API进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:根据官方提供的benchmark数据,单实例支持每秒2k+读操作
- 可靠:采用raft算法,实现分布式系统数据的可用性和一致性
1.2 安装环境
本实验需要两台服务器,如下表所示。
|
操作系统 |
内存 |
CPU |
IP地址 |
主机名 |
服务器1 |
Centos 7.5 |
32G |
双核四线程CPU * 2 |
10.40.239.234 |
node234 |
服务器2 |
Centos 7.5 |
32G |
双核四线程CPU * 2 |
10.40.239.235 |
node235 |
2 操作流程
2.1 对服务器校时
这里我们使用国家授时中心NTP(Network Time Protocol)服务对两台服务器校时:
ntpdate ntp.ntsc.ac.cn
2.2 安装etcd
在两台服务器上执行下面的命令,安装etcd:
yum -y install etcd
执行下面的命令,查看etcd:
yum list installed |grep -i etcd
如果出现如下结果,表示安装成功:
etcd.x86_64 3.3.11-2.el7.centos @extras
2.3 配置etcd
2.3.1 node234 上的配置
1. 备份原先的etcd配置文件。
cp
/etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak
2
.编辑配置文件:
vi /etc/etcd/etcd.conf
配置如下内容:
ETCD_DATA_DIR="/var/lib/etcd/node234.etcd" ETCD_LISTEN_PEER_URLS="http://10.40.239.234:2380" ETCD_LISTEN_CLIENT_URLS="http://10.40.239.234:2379,http://localhost:2379" ETCD_NAME="node234" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.40.239.234:2380" ETCD_ADVERTISE_CLIENT_URLS="http://10.40.239.234:2379" ETCD_INITIAL_CLUSTER="node234=http://10.40.239.234:2380, node235=http://10.40.239.235:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="new"
这里解释一下这些参数的含义:
ETCD_DATA_DIR:数据存储目录。由etcd自动创建。
ETCD_LISTEN_PEER_URLS:监听在对等节点流量上的URL列表,该参数告诉etcd在指定的 “协议://IP:端口”组合上接收来自其对等方的传入请求。协议可以是http或者https。或者,使用unix://<file-path>或者unixs://<file-path>到unix sockets。如果将0.0.0.0作为IP,etcd将监听在所有的接口上的给定端口。如果给定了IP和端口,etcd将监听指定的接口和端口。可以使用多个URL指定要监听的地址和端口的数量。 etcd将响应来自任何列出的地址和端口的请求。
ETCD_LISTEN_CLIENT_URLS:监听在客户端流量上的URL列表,该参数告诉etcd在指定的“协议://IP:端口”组合上接受来自客户端的传入请求。协议可以是http或者https。或者,使用unix://<file-path>或者unixs://<file-path>到unix sockets。如果将0.0.0.0作为IP,etcd将监听在所有的接口上的给定端口。如果给定了Ip和端口,etcd将监听指定的接口和端口。可以使用多个URL指定要监听的地址和端口的数量。 etcd将响应来自任何列出的地址和端口的请求。
ETCD_NAME:此成员的名字。
ETCD_INITIAL_ADVERTISE_PEER_URLS:此成员对等URL的列表,用来通知到集群的其余部分。 这些地址用于在集群周围传送etcd数据。 所有集群成员必须至少有一个路由。 这些URL可以包含域名。
ETCD_ADVERTISE_CLIENT_URLS:此成员的客户端URL的列表,这些URL广播给集群的其余部分。 这些URL可以包含域名。
ETCD_INITIAL_CLUSTER:启动集群的初始化配置。配置集群的成员。
ETCD_INITIAL_CLUSTER_TOKEN:引导期间etcd群集的初始集群令牌。
ETCD_INITIAL_CLUSTER_STATE:初始群集状态(“新”或“现有”)。 对于在初始静态或DNS引导过程中存在的所有成员,将其设置为new。 如果此选项设置为existing,则etcd将尝试加入现存集群。 如果设置了错误的值,etcd将尝试启动,但会安全地失败。
更多信息,可以参照etcd官方文档。
2.3.1 node235 上的配置
1. 备份原先的etcd配置文件。
cp
/etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak
2
.编辑配置文件:
ETCD_DATA_DIR="/var/lib/etcd/node235.etcd" ETCD_LISTEN_PEER_URLS="http://10.40.239.235:2380" ETCD_LISTEN_CLIENT_URLS="http://10.40.239.235:2379,http://localhost:2379" ETCD_NAME="node235" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.40.239.235:2380" ETCD_ADVERTISE_CLIENT_URLS="http://10.40.239.235:2379" ETCD_INITIAL_CLUSTER="node234=http://10.40.239.234:2380,node235=http://10.40.239.235:2380" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster" ETCD_INITIAL_CLUSTER_STATE="new"
2.4 修改etcd.service
在两台服务器上,分别修改服务启动文件 /usr/lib/systemd/system/etcd.service,内容设置如下:
[Service] Type=notify WorkingDirectory=/var/lib/etcd/ EnvironmentFile=-/etc/etcd/etcd.conf User=etcd # set GOMAXPROCS to number of processors ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd \ --name=\"${ETCD_NAME}\" \ --data-dir=\"${ETCD_DATA_DIR}\" \ --listen-peer-urls=\"${ETCD_LISTEN_PEER_URLS}\" \ --listen-client-urls=\"${ETCD_LISTEN_CLIENT_URLS}\" \ --initial-advertise-peer-urls=\"${ETCD_INITIAL_ADVERTISE_PEER_URLS}\" \ --advertise-client-urls=\"${ETCD_ADVERTISE_CLIENT_URLS}\" \ --initial-cluster=\"${ETCD_INITIAL_CLUSTER}\" \ --initial-cluster-token=\"${ETCD_INITIAL_CLUSTER_TOKEN}\" \ --initial-cluster-state=\"${ETCD_INITIAL_CLUSTER_STATE}\"" Restart=on-failure LimitNOFILE=65536
2.5 启动 etcd
依次启动 node234和node235节点的 etcd
systemctl start etcd.service
设置允许开机启动:
systemctl enable etcd.service
2.6
查看etcd的状态
执行下列命令,验证etcd的状态:
etcdctl cluster-health
结果:
member 5a4542289ef36c64 is healthy: got healthy result from http://10.40.239.234:2379
member f792ada069403352 is healthy: got healthy result from http://10.40.239.235:2379
查看etfd 结点列表:
etcdctl member list
结果:
5a4542289ef36c64: name=node234 peerURLs=http://10.40.239.234:2380 clientURLs=http://10.40.239.234:2379 isLeader=true
f792ada069403352: name=node236 peerURLs=http://10.40.239.235:2380 clientURLs=http://10.40.239.236:2379 isLeader=false