在 RHEL 或 CentOS 上使用 Patroni 部署 PostgreSQL 以實現高可用性

wongchaofan發表於2024-08-09

本指南提供了有關如何在 Red Hat Enterprise Linux 或 CentOS 上使用 Patroni 設定高可用性 PostgreSQL 叢集的說明。

注意事項

  1. 這是一個示例部署,其中 etcd 與 Patroni 和 PostgreSQL 在同一臺主機上執行,​​並且有一個專用的 HAProxy 主機。或者,etcd 可以在不同的節點集上執行。

    如果 etcd 與 Patroni 和 PostgreSQL 部署在同一臺主機上,出於效能原因,建議為 etcd 和 PostgreSQL 使用單獨的磁碟系統。

對於此設定,我們使用執行 Red Hat Enterprise Linux 8 的節點作為基礎作業系統:

節點名稱應用IP地址
節點1 Patroni、PostgreSQL、etcd 10.104.0.1
節點2 Patroni、PostgreSQL、etcd 10.104.0.2
節點3 Patroni、PostgreSQL、etcd 10.104.0.3
HAProxy 演示 HAProxy 10.104.0.6
由於存在安全風險,我們建議不要將執行 Patroni / etcd / PostgreSQL 的主機/節點暴露到公共網路。使用防火牆、虛擬網路、子網等保護資料庫主機免受任何型別的攻擊。

初始設定

/etc/hosts在檔案中設定主機名

名稱解析不是必需的,但它使整個設定更易讀且更不容易出錯。在這裡,我們不是配置 DNS,而是透過更新檔案來使用本地名稱解析/etc/hosts。透過將其主機名解析為其 IP 地址,我們使節點知道彼此的名稱並允許它們無縫通訊。

  • 在每個節點上執行以下命令。將節點名稱分別更改為node1node2node3

sudo hostnamectl set-hostname node-1
  • 修改每個 PostgreSQL 節點的檔案,使其包含其餘節點的主機名和 IP 地址。在所有節點上的檔案/etc/hosts末尾新增以下內容:/etc/hosts

節點

# Cluster IP and names 
10.104.0.1 node1 
10.104.0.2 node2 
10.104.0.3 node3

HAproxy 演示

HAProxy 例項應在其檔案中具有所有三個節點的名稱解析/etc/hosts。在檔案末尾新增以下幾行:

# Cluster IP and names
10.104.0.6 HAProxy-demo
10.104.0.1 node1
10.104.0.2 node2
10.104.0.3 node3

安裝軟體

在 上安裝 Percona Distribution for PostgreSQL node1node2node3從 Percona 儲存庫安裝:

安裝一些 Python 和輔助包來幫助 Patroni 和 etcd

sudo yum install python3-pip python3-devel binutils

安裝 etcd、Patroni、pgBackRest 包。

sudo yum install percona-patroni \
etcd python3-python-etcd\
percona-pgbackrest

停止並禁用所有已安裝的服務:

sudo systemctl stop {etcd,patroni,postgresql}
systemctl disable {etcd,patroni,postgresql}

配置 etcd 分散式儲存

分散式配置儲存提供了一種可靠的方法來儲存需要由大規模分散式系統訪問的資料。最流行的分散式配置儲存實現是 etcd。etcd 部署為叢集以實現容錯,並且需要奇數個成員 (n/2+1) 才能就叢集狀態的更新達成一致。etcd 叢集有助於在故障轉移期間在節點之間建立共識,並管理三個 PostgreSQL 例項的配置。

叢集etcd首先在一個節點上啟動,然後使用命令將後續節點新增到第一個節點上add

配置node1

  • 建立配置檔案。您可以編輯示例配置檔案/etc/etcd/etcd.conf.yaml或建立自己的配置檔案。將節點名稱和 IP 地址替換為您節點的實際名稱和 IP 地址。
/etc/etcd/etcd.conf.yaml
name: 'node1' #成員的可讀性的名字. initial-cluster-token: PostgreSQL_HA_Cluster_1 #在啟動期間用於 etcd 叢集的初始化叢集記號(cluster token)。 initial-cluster-state: new #初始化叢集狀態("new" or "existing")。在初始化靜態(initial static)或者 DNS 啟動 (DNS bootstrapping) 期間為所有成員設定為 new 。如果這個選項被設定為 existing , etcd 將試圖加入已有的叢集。如果設定為錯誤的值,etcd 將嘗試啟動但安全失敗。 initial-cluster: node1=http://10.104.0.1:2380 #為啟動初始化叢集配置。 data-dir: /var/lib/etcd #資料目錄的路徑 initial-advertise-peer-urls: http://10.104.0.1:2380 #列出這個成員的夥伴 URL 以便通告給叢集的其他成員。預設:"http://localhost:2380" listen-peer-urls: http://10.104.0.1:2380 #用於監聽夥伴通訊的URL列表。 advertise-client-urls: http://10.104.0.1:2379 #列出這個成員的客戶端URL,預設: "http://localhost:2379" listen-client-urls: http://10.104.0.1:2379 #用於監聽客戶端通訊的URL列表。

啟動etcd服務以應用更改node1

sudo systemctl enable --now etcd
sudo systemctl status etcd

檢查 etcd 叢集成員node1

sudo etcdctl member lis

示例輸出:

21d50d7f768f153a: name=default peerURLs=http://10.104.0.5:2380 clientURLs=http://10. 104.0.5:2379 isLeader=true

新增node2到叢集。在 node1上執行以下命令

$ sudo etcdctl member add node2 http://10.104.0.2:2380
Added member named node2 with ID 10042578c504d052 to cluster

etcd_NAME="node2"
etcd_INITIAL_CLUSTER="node2=http://10.104.0.2:2380,node1=http://10.104.0.1:2380"
etcd_INITIAL_CLUSTER_STATE="existing"

配置node2

建立配置檔案。您可以編輯示例配置檔案/etc/etcd/etcd.conf.yaml或建立自己的配置檔案。將節點名稱和 IP 地址替換為您節點的實際名稱和 IP 地址。

/etc/etcd/etcd.conf.yaml

name: 'node2'
initial-cluster-token: PostgreSQL_HA_Cluster_1
initial-cluster-state: existing
initial-cluster: node1=http://10.104.0.1:2380,node2=http://10.104.0.2:2380
data-dir: /var/lib/etcd
initial-advertise-peer-urls: http://10.104.0.2:2380 
listen-peer-urls: http://10.104.0.2:2380
advertise-client-urls: http://10.104.0.2:2379
listen-client-urls: http://10.104.0.2:2379

啟動etcd服務以應用更改node2

sudo systemctl enable --now etcd
sudo systemctl status etcd

配置node3

新增node3到叢集。node1上執行以下命令

sudo etcdctl member add node3 http://10.104.0.3:2380

在 node3上,建立配置檔案。您可以編輯示例配置檔案/etc/etcd/etcd.conf.yaml或建立自己的配置檔案。將節點名稱和 IP 地址替換為您的節點的實際名稱和 IP 地址:

/etc/etcd/etcd.conf.yaml

name: 'node1'
initial-cluster-token: PostgreSQL_HA_Cluster_1
initial-cluster-state: existing
initial-cluster: node1=http://10.104.0.1:2380,node2=http://10.104.0.2:2380,node3=http://10.104.0.3:2380
data-dir: /var/lib/etcd
initial-advertise-peer-urls: http://10.104.0.3:2380 
listen-peer-urls: http://10.104.0.3:2380
advertise-client-urls: http://10.104.0.3:2379
listen-client-urls: http://10.104.0.3:2379

啟動etcd服務以應用更改。

sudo systemctl enable --now etcd
sudo systemctl status etcd

檢查 etcd 叢集成員。

sudo etcdctl member list
2d346bd3ae7f07c4: name=node2 peerURLs=http://10.104.0.2:2380 clientURLs=http://10.104.0.2:2379     isLeader=false
8bacb519ebdee8db: name=node3 peerURLs=http://10.104.0.3:2380 clientURLs=http://10.104.0.3:2379     isLeader=false
c5f52ea2ade25e1b: name=node1 peerURLs=http://10.104.0.1:2380 clientURLs=http://10.104.0.1:2379     isLeader=true

配置 Patroni

在所有節點上執行以下命令。您可以並行執行此操作:

  1. 匯出並建立環境變數以簡化配置檔案的建立:

    • 節點名稱:
export NODE_NAME=`hostname -f` #
  • 節點 IP:
export NODE_IP=`hostname -i | awk '{print $1}'`
  • 建立變數來儲存 PATH:
DATA_DIR="/var/lib/pgsql/data/"
PG_BIN_DIR="/usr/pgsql-15/bin"

注意:檢查作業系統上資料和 bin 資料夾的路徑,並相應地更改變數。

  • 贊助人資訊:
NAMESPACE="percona_lab"
SCOPE="cluster_1

建立 Patroni 所需的目錄

  • 建立用於儲存配置檔案的目錄並使其歸使用者所有postgres
sudo mkdir -p /etc/patroni/
sudo chown -R  postgres:postgres /etc/patroni/
  • 建立資料目錄來儲存 PostgreSQL 資料。將其所有權更改為使用者postgres並限制對它的訪問
sudo mkdir /data/pgsql -p
sudo chown -R postgres:postgres /data/pgsql
sudo chmod 700 /data/pgsql

建立/etc/patroni/patroni.yml配置檔案。新增以下配置:

echo "
namespace: ${NAMESPACE}
scope: ${SCOPE}
name: ${NODE_NAME}

restapi:
    listen: 0.0.0.0:8008
    connect_address: ${NODE_IP}:8008

etcd3:
    host: ${NODE_IP}:2379

bootstrap:
  # this section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
  dcs:
      ttl: 30
      loop_wait: 10
      retry_timeout: 10
      maximum_lag_on_failover: 1048576
      slots:
          percona_cluster_1:
            type: physical

      postgresql:
          use_pg_rewind: true
          use_slots: true
          parameters:
              wal_level: replica
              hot_standby: "on"
              wal_keep_segments: 10
              max_wal_senders: 5
              max_replication_slots: 10
              wal_log_hints: "on"
              logging_collector: 'on'

  # some desired options for 'initdb'
  initdb: # Note: It needs to be a list (some options need values, others are switches)
      - encoding: UTF8
      - data-checksums

  pg_hba: # Add following lines to pg_hba.conf after running 'initdb' #初始化叢集后配置設定
      - host replication replicator 127.0.0.1/32 trust
      - host replication replicator 0.0.0.0/0 md5
      - host all all 0.0.0.0/0 md5
      - host all all ::0/0 md5

  # Some additional users which needs to be created after initializing new cluster,#資料庫需要建立的使用者
  users:
      admin:
          password: qaz123
          options:
              - createrole
              - createdb
      percona:
          password: qaz123
          options:
              - createrole
              - createdb 

postgresql:
    cluster_name: cluster_1
    listen: 0.0.0.0:5432
    connect_address: ${NODE_IP}:5432
    data_dir: ${DATA_DIR}
    bin_dir: ${PG_BIN_DIR}
    pgpass: /tmp/pgpass
    authentication:
        replication:
            username: replicator
            password: replPasswd
        superuser:
            username: postgres
            password: qaz123
    parameters:
        unix_socket_directories: "/var/run/postgresql/"
    create_replica_methods:
        - basebackup
    basebackup:
        checkpoint: 'fast'

tags:
    nofailover: false
    noloadbalance: false
    clonefrom: false
    nosync: false
" | sudo tee -a /etc/patroni/patroni.yml

檢查 systemd 單元檔案patroni.service是否已在 /etc/systemd/system中建立。如果已建立,請跳過此步驟。

若未建立,請手動建立,並在其中指定以下內容:

/etc/systemd/system/patroni.service

[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target 

[Service]
Type=simple 

User=postgres
Group=postgres 

# Start the patroni process
ExecStart=/bin/patroni /etc/patroni/patroni.yml 

# Send HUP to reload from patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID 

# only kill the patroni process, not its children, so it will gracefully stop postgres
KillMode=process 

# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=30 

# Do not restart the service if it crashes, we want to manually inspect database on failure
Restart=no 

[Install]
WantedBy=multi-user.target

瞭解systemd新服務:

sudo systemctl daemon-reload

現在是時候啟動 Patroni 了。您需要在所有節點上(但不是並行)執行以下命令。從node1第一個節點開始,等待服務上線,然後逐個處理其他節點,始終等待它們與主節點同步:

sudo systemctl enable --now patroni
sudo systemctl restart patroni

當 Patroni 啟動時,它會按照配置檔案引導部分中的指令初始化 PostgreSQL(因為該服務當前未執行且資料目錄為空)。

  1. 檢查服務是否有錯誤:

sudo journalctl -fu patroni

一個常見錯誤是 Patroni 抱怨 pg_hba.conf 檔案中缺少正確的條目。如果您看到此類錯誤,則必須手動新增或修復該檔案中的條目,然後重新啟動服務。

更改 patroni.yml 檔案並重新啟動服務不會產生任何影響,因為 bootstrap 部分指定了在節點中首次啟動 PostgreSQL 時要應用的配置。即使修改了 Patroni 配置檔案並重新啟動服務,它也不會重複該過程。

如果 Patroni 已正確啟動,您應該能夠使用以下命令本地連線到 PostgreSQL 節點:

sudo psql -U postgres

psql (15.4)
Type "help" for help.

postgres=#

當所有節點都啟動並執行時,您可以使用以下命令檢查叢集狀態:

sudo patronictl -c /etc/patroni/patroni.yml list

輸出node1類似以下內容:

+ Cluster: cluster_1 --+---------+---------+----+-----------+
| Member | Host        | Role    | State   | TL | Lag in MB |
+--------+-------------+---------+---------+----+-----------+
| node-1 | 10.0.100.1  | Leader  | running |  1 |           |
+--------+-------------+---------+---------+----+-----------+

在其餘節點上:

+ Cluster: cluster_1 --+---------+---------+----+-----------+
| Member | Host        | Role    | State   | TL | Lag in MB |
+--------+-------------+---------+---------+----+-----------+
| node-1 | 10.0.100.1  | Leader  | running |  1 |           |
| node-2 | 10.0.100.2  | Replica | running |  1 |         0 |
+--------+-------------+---------+---------+----+-----------+

配置 HAProxy

HAproxy 是負載均衡器,也是客戶端應用程式進入 PostgreSQL 叢集的單一入口點。客戶端應用程式訪問 HAPpoxy URL 並將其讀/寫請求傳送到那裡。在後臺,HAProxy 以迴圈方式將寫入請求路由到主節點,將讀取請求路由到輔助節點,這樣就不會不必要地載入輔助例項。要實現這一點,請在 HAProxy 配置檔案中提供不同的埠。在此部署中,寫入被路由到埠 5000,讀取被路由到埠 5001

這樣,客戶端應用程式就不知道底層叢集中的哪個節點是當前主節點。HAProxy 將連線傳送到健康節點(只要至少有一個健康節點可用),並確保客戶端應用程式請求永遠不會被拒絕。

  1. 在節點上安裝 HAProxy HAProxy-demo

sudo yum install percona-haproxy

HAProxy 配置檔案路徑為:/etc/haproxy/haproxy.cfg。在此檔案中指定以下配置。

global
    maxconn 100

defaults
    log global
    mode tcp
    retries 2
    timeout client 30m
    timeout connect 4s
    timeout server 30m
    timeout check 5s

listen stats   #“listen”部分定義了一個完整的代理,其前端和後端部分合並在一個部分中。它通常適用於僅 TCP 流量。
    mode http
    bind *:7000
    stats enable
    stats uri /

listen primary
    bind *:5000
    option httpchk /primary   #後端,啟用 HTTP 協議檢查伺服器健康狀況,option httpchk <method> <uri> <version>,method是http中的方法,可省略;uri是http中的路徑;
    http-check expect status 200   #後端,定義以下 http-check 規則的註釋,如果失敗則在日誌中報告。使 HTTP 健康檢查考慮響應內容或特定狀態程式碼,配合上面使用
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions   #後端,更改後端伺服器的預設選項,inter ”引數將兩次連續健康檢查之間的間隔設定為 <delay> 毫秒;fall ” 參數列示伺服器在連續 <count> 次健康檢查失敗後將被視為已死亡。如果未指定,此值預設為 3;rise ”參數列示在連續 <count> 次成功健康檢查後,伺服器將被視為正常執行;on-marked-down修改伺服器被標記為關閉時發生的情況。目前有一個操作可用:-shutdown-sessions:關閉對等會話。啟用此設定後,伺服器關閉時所有與伺服器的連線都會立即終止。
    server node1 node1:5432 maxconn 100 check port 8008
    server node2 node2:5432 maxconn 100 check port 8008
    server node3 node3:5432 maxconn 100 check port 8008

listen standbys
    balance roundrobin
    bind *:5001
    option httpchk /replica 
    http-check expect status 200  #後端
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server node1 node1:5432 maxconn 100 check port 8008  #check此選項啟用伺服器上的執行狀況檢查: - 未設定時,不執行執行狀況檢查,並且始終認為伺服器可用。可以使用“ addr ”更改目標地址,使用“ port ”更改埠。
    server node2 node2:5432 maxconn 100 check port 8008
    server node3 node3:5432 maxconn 100 check port 8008
  1. HAProxy 將使用 Patroni 託管的 REST API 來檢查每個 PostgreSQL 節點的健康狀態並適當地路由請求。

  2. 啟用 SELinux 布林值以允許 HAProxy 繫結到非標準埠:

sudo setsebool -P haproxy_connect_any on

重新啟動 HAProxy:

sudo systemctl restart haproxy

檢查 HAProxy 日誌以檢視是否有任何錯誤:

sudo journalctl -u haproxy.service -n 100 -f


來源: https://docs.percona.com/postgresql/15/solutions/high-availability.html

https://www.haproxy.com/documentation/haproxy-configuration-tutorials/alerts-and-monitoring/prometheus/

https://www.haproxy.com/documentation/haproxy-configuration-manual/2-6r1/#4-server

相關文章