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