PostgreSQL 高可用集羣在 360 的落地實戰
本文主要從以下幾個方面介紹 PostgreSQL 高可用集羣在 360 的落地實戰
爲什麼選擇 Patroni + Etcd + PostgreSQL 高可用集羣方案
PostgreSQL 高可用集羣在 360 的落地實戰 Patroni + Etcd 高可用集羣架構解析
Patroni + Etcd + PostgreSQL 部署實戰
Patroni 日常運維管理
PostgreSQL 監控實現
PostgreSQL 應用連接方式
PostgreSQL 備份恢復方式選擇
背景
最近線上重要業務容器雲的鏡像倉庫需要部署一套 postgresql 高可用集羣,涉及到數據庫選型,最終選擇了 postgresql,爲什麼不選擇 mysql 呢,postgresql 是功能最強大的開源數據庫,主要考慮 postgresql 支持使用函數索引和條件索引,text 沒有限制,可以索引,還可以全文檢索,不用再接一套 es,並且 postgresql 開源協議好,開源軟件原生支持好,特別對開發來說比較友好,最重要的是 kube-bench 只支持 postgresql。
爲什麼選擇 Patroni + Etcd 方案
PostgreSQL 比較流行的高可用解決方案有很多,常用的主要包含 repmgr 和 patroni 等,也是 github star 前幾的高可用組件,並且文檔更新比較及時,都可最高支持 postgresql 13,repmgr 相對來說功能沒有 patroni 全面以及不能檢測備機是否被錯誤配置爲未知或不存在的節點、不能檢測遠程節點的狀態(不具備分佈式解決方案)和不能處理單個節點的恢復,本文主要基於 patroni 實現。
此方案使用 Patroni 管理本地庫,並結合 Etcd 作爲數據存儲和主節點選舉, 具有以下優勢:
-
健壯性**: **使用分佈式 key-value 數據庫作爲數據存儲,主節點故障時進行主節點重新選舉,具有很強的健壯性
-
支持多種複製方式**: **基於內置流複製,支持同步流複製、異步流複製、級聯複製
-
**支持主備延遲設置: **可以設置備庫延遲主庫 WAL 的字節數,當備庫延遲大於指定值時不做故障切換
-
** 自動化程****度高:**
-
支持自動化初始 PostgreSQL 實例並部署流複製
-
當備庫實例關閉後,支持自動拉起
-
當主庫實例關閉後,首先會嘗試自動拉起
-
支持 switchover 命令,能自動將老的主庫進行角色轉換
- **避免腦裂: **數據庫信息記錄到 ETCD 中,通過優化部署策略(多機房部署、增加實例數) 可以避免腦裂
Patroni + Etcd 高可用架構
Patroni 是一個開源工具套件,它是用 Python 編寫的,可確保 PostgreSQL HA 集羣的端到端設置,包括流複製。它的功能通過 REST API 顯示,也通過一個名爲 Patronictl 的命令行實用程序顯示。它通過使用其運行狀況檢查 API 來處理負載平衡來支持與 HAProxy 的集成。在此 HA 解決方案中,etcd 用於分佈式配置存儲 (DCS),以實現最大的可訪問性, 下面是官方高可用集羣方案的架構圖展示,我們基於此完成 postgresql 高可用架構集羣方案設計,不過並沒有使用 HAproxy 進行負載均衡,而是使用公司內部的 LVS 來實現的,一主兩副本,副本部署在不同的 idc 實現異地災備,etcd 也是三節點集羣分別部署在三臺機器, 如果資源有限, 也可以和 postgresql/patroni 部署在相同機器。
Etcd、Patroni 和 PostgreSQL 是如何一起工作的
etcd/patroni/postgresql 都是部署的 3 節點集羣
Etcd: 分佈式的 Key-Value 數據庫
etcd1、etcd2、 etcd3 作爲分佈式的 Key-Value 數據庫,被 partroni1、 patroni2、 patroni3 讀 / 寫,用於共享 / 傳遞信息。每一個 Patroni 都能讀 / 寫 etcd 中的數據。
Paroni: 控制 / 監控本地的 PostgreSQL, 把本地 PostgreSQL 信息 / 狀態寫入 etcd
每一個 Patroni 實例監控 / 控制本地的 PostgreSQL,把本地本地 PostgreSQL 信息 / 狀態寫入 etcd , 一個 Patroni 實例能夠通過讀取 etcd 獲取外地 PostgreSQL 的信息 / 狀態。
PostreSQL 主節點的****選舉
Patroni 判斷本地 PostgreSQL 是否可以作爲 Primary 庫。如果可以,Paroni 試圖選舉本地 PostgreSQL 作爲 Primary(Leader) , 選舉方式是:把 etcd 中的某個 key 更新成爲本地 PostgreSQL 的名字, 如果多個 Paroni 同時更改同一個 key,只有一個能改成功,然後成爲 Primary(Leader)。
部署篇
系統 / 軟件 / 版本
· CentOS 7.4
· PostgreSQL 12.6
· etcd: 3.2.18
· python: Python 3.6.5
· Patroni: 2.1.0
主機信息
10.16.75.17 pg12/patroni
10.16.75.15 pg12/patroni
10.16.78.53 pg12/patroni
10.24.13.9 etcd
10.24.13.10 etcd
10.24.13.11 etcd
這裏用了 6 臺機器,也可以用 3 臺機器組件全部安裝在一起
Python3 安裝
安裝依賴
yum install wget gcc make zlib-devel openssl openssl-devel
wget "https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tar.xz"
tar -xvJf Python-3.6.5.tar.xz
編譯
cd Python-3.6.5 && ./configure prefix=/usr/local/python3
make && make install
ln -fs /usr/local/python3/bin/python3 /usr/bin/python3
ln -fs /usr/local/python3/bin/pip3 /usr/bin/pip3
virtualenv
pip3 install virtualenv -i https://mirrors.ustc.edu.cn/pypi/web/simple/
ln -fs /usr/local/python3/bin/virtualenv /usr/bin/virtualenv
編譯安裝 python 的使用
cd /data04 && virtualenv venv4archery --python=python3
切換 python 運行環境到虛擬環境
source venv4archery/bin/activate
創建 PG 目錄和用戶
useradd postgres #編譯安裝的,yum 安裝不用創建
mkdir -p /data04/pg15432
mkdir -p /data04/pg15432/data
mkdir -p /data04/pg15432/scripts
chown -R postgres:postgres /data04/pg15432/
創建歸檔目錄
mkdir -p /data04/pg15432/arch
源碼安裝 postgresql12
yum -y install -y readline-devel
mkdir -p /usr/local/pgsql/
./configure --prefix=/usr/local/pgsql
make && make install
cp /usr/local/pgsql/bin/* /sbin/
Etcd 部署
yum install etcd -y
編輯 / etc/etcd/etcd.conf 配置文件
Etcdnode1 配置
ETCD_DATA_DIR="/var/lib/etcd/codis.etcd"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.24.13.9:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.24.13.9:2379"
ETCD_INITIAL_CLUSTER="node1=http://10.24.13.9:2380,node2=http://10.24.13.10:2380,node3=http://10.24.13.11:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
Etcd node2 配置
ETCD_DATA_DIR="/var/lib/etcd/codis.etcd"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.24.13.10:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.24.13.10:2379"
ETCD_INITIAL_CLUSTER="node1=http://10.24.13.9:2380,node2=http://10.24.13.10:2380,node3=http://10.24.13.11:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
Etcd node3 配置
ETCD_DATA_DIR="/var/lib/etcd/codis.etcd"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.24.13.11:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://10.24.13.11:2379"
ETCD_INITIAL_CLUSTER="node1=http://10.24.13.9:2380,node2=http://10.24.13.10:2380,node3=http://10.24.13.11:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
#注意 etcdnode1 每個節點都不一樣,etcd-cluster-1 是集羣名字統一
systemctl daemon-reload
systemctl enable etcd
systemctl start etcd
Etcd 成員列表顯示
etcdctl member list
Etcd 集羣健康檢查
etcdctl --endpoints http://10.24.13.9:2379 cluster-health
Patronic 部署
cd /data04 && virtualenv venv4archery --python=python3
source venv4archery/bin/activate
pip3 install psycopg2-binary -i https://mirrors.aliyun.com/pypi/simple/
或者 pip3 install psycopg2>=2.5.4 -i https://mirrors.aliyun.com/pypi/simple/
pip3 install patroni[etcd,consul,zookeeper,kubernetes] -i https://mirrors.aliyun.com/pypi/simple/
#啓動 patroni 集羣需非 root 用戶
集羣進行初始化**(****所有節點執行****)**
patroni /etc/patroni.yml > patroni_member_1.log 2>&1 &
可以使用 centos7 的 service 啓動:
[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target
[Service]
Type=simple
User=postgres
Group=postgres
#StandardOutput=syslog
ExecStart=/sbin/patroni /etc/patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no
[Install]
WantedBy=multi-user.target
/etc/patroni.yml** (****可根據自己需求定製化****)**
scope: postgresql
namespace: /service/
name: postgresql1
restapi:
listen: 10.16.75.17:8008
connect_address: 10.16.75.17:8008
etcd:
host: 10.24.13.9:2379
host: 10.24.13.10:2379
host: 10.24.13.11:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
listen_addresses: "0.0.0.0"
**wal_level: logical **
** archive_mode: "on" **
** max_connections: 6000**
S****hared_buffers: 32GB
archive_command: 'DATE=date +%Y%m%d
;DIR="/data04/pg15432/arch/$DATE";(test -d $DIR || mkdir -p $DIR)&& cp %p $DIR/%f'
hot_standby: "on"
wal_keep_segments: 100
max_wal_senders: 10
max_replication_slots: 10
wal_log_hints: "on"
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication repl 127.0.0.1/32 md5
- host replication repl 10.16.75.17/0 md5
- host replication repl 10.16.75.15/0 md5
- host replication repl 10.206.87.218/0 md5
- host replication repl 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql:
listen: 10.16.75.17:15432
connect_address: 10.16.75.17:15432
bin_dir: /usr/local/pgsql/bin
data_dir: /data04/pg15432/data
pgpass: /tmp/pgpass1
authentication:
replication:
username: repl
password: "1a23s6c54f"
superuser:
username: postgres
password: "59687411134be622"
parameters:
unix_socket_directories: '.'
synchronous_commit: "on"
synchronous_standby_names: "*"
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
重點關注上面標紅的參數設置,如果初始化未設置也沒關係,部署完成一定驗證下重要參數設置,未設置的可以通過 patronictl 進行設置。
PG 集羣信息查看
數據庫賬戶創建
CREATE USER docker WITH PASSWORD 'xxxx';
CREATE DATABASE docker OWNER docker;
GRANT ALL PRIVILEGES ON DATABASE docker to docker;
遠程連接數據庫
psql -U docker -d docker -p xxxx-h xxxx
嘗試對主節點進行讀寫
以上完成對整個集羣的部署並確保數據庫可以正常進行讀寫
Patronictl 日常運維
參數設置查看
shared_buffers
類似 mysql innodb_buffer_pool_size,該參數主要設置數據庫服務器將使用的共享內存緩衝區量,建議是設置系統內存的 25%,過高也會造成一些工作負載,還是需要跟業務溝通獲取預估的數據量以及估算熱數據量來針對性制定參數值。
修改 shared_buffers
patronictl -c /etc/patroni.yml edit-config -p "shared_buffers='32GB'"
patronictl -c /etc/patroni.yml restart postgresql (重啓生效)
max_connections
決定數據庫的最大併發連接數。默認值通常是 100 個連接,但是如果內核設置不支持(initdb 時決定),可能會比這個 數少。這個參數只能在服務器啓動時設置。
當運行一個後備服務器時,你必須設置這個參數等於或大於主服務器上的參數。否則,後備服務器上可能無法允許查詢。
修改 max_connections
patronictl -c /etc/patroni.yml edit-config -p 'max_connections=6000'
patronictl -c /etc/patroni.yml restart postgresql (重啓生效)
查看當前歸檔日誌
select pg_walfile_name(pg_current_wal_lsn());
手動切換歸檔
select pg_walfile_name(pg_current_wal_lsn());
可以看到歸檔已經由...0000B 切換到...0000C
設置開啓慢日誌
閾值爲 200ms
patronictl -c /etc/patroni.yml edit-config -p 'log_min_duration_statement=200'
查看慢日誌設置閾值
高可用故障轉移測試
Kill 主節點進程
會發現 patroni 會自動拉起 postgresql 進程,並且還是主節點,並未進行切主
手工切主
假設切主到 postgresql2 155 節點
patronictl -d etcd://10.16.75.17:2379 switchover postgresql
切主期間會出現中間狀態 unknown,瞬間會恢復正常如下,切主成功到 155。
重啓集羣
可看到主節點也是沒切主,拓撲和以前是一樣的。
主 / 從節點機器重啓
機器宕機是常有的事情,當 postgresql 某個節點所在機器宕機恢復後,需要手動拉起節點 patroni /etc/patroni.yml > patroni_member_1.log 2>&1 &
禁用開啓故障轉移
當 pause 後,這時候集羣是不會進行自動故障轉移的,可以在某些特定場景使用,然後用 resume 恢復就可以了。
還有其它一些功能可以參考 patronictl --help
PostgreSQL 監控
監控是眼睛,對於運維來說非常重要,這邊主要採用的是 Grafana + Prometheus 監控 PostgreSQL,自帶 PG 監控指標模版,也可自己定製詳盡指標,結合內部告警平臺編寫 api 實現告警短信發送以及推推內部溝通軟件推送,具體部署這裏就不詳細闡述了, 監控界面如下:
監控參考:
https://www.bbsmax.com/A/pRdBKG0Pzn/
dashboard json 下載模版
https://grafana.com/grafana/dashboards?search=postgresql&orderBy=reviewsCount&direction=desc
下載好 json 文件直接在 dashboard 倒入模版即可
監控指標 rules 可自己定製,可選擇常用的,比較重要的指標即可
應用連接方式
這邊採用的是公司內部的 lvs 機制,通過掛載 vip 的方式來實現讀寫分離,也可以通過 haproxy 等組件來實現負載均衡,多一層組件就會多一層故障點,同樣需要保證高可用,可根據業務重要程度進行抉擇。
PostgreSQL 備份
PostgreSQL 流複製備份可選擇物理備份或者邏輯備份,邏輯備份可選擇 pg_dump 進行單表備份或者 pg_dumpall 進行全庫備份,物理備份可選擇 pg_basebackup 或者 pg_rman 備份,在此我選擇 pg_rman 進行備份,下面重點介紹下強大的 pg_rman 備份工具。
pg_rman 是一個開源的 PostgreSQL 備份管理軟件,類似 Oracle 的 RMAN,使用的是 pg_start_backup(), copy, pg_stop_backup() 的備份模式,pg_rman 跑的不是流複製協議,而是文件拷貝,所以 pg_rman 必須和數據庫節點跑在一起,如果在 standby 節點運行 pg_rman,pg_rman 則需要通過網絡連接到主節點執行 pg_start_backup/pg_stop_backup。
pg_rman 可支持的主要功能如下:
-
全量備份
-
增量備份
-
檢驗備份集
-
列出備份集
-
按指定時間從 catalog 刪除備份集
-
物理刪除已從 catalog 刪除的備份集
相信用過 oracle 的同學瞭解 oracle rman 備份的強大就清楚 pg_rman 的功能強大之處,具體可參考 http://mysql.taobao.org/monthly/2016/09/05/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/FywWRrrZMQ3It7kHTDshog