PostgreSQL高可用集群在360的落地實(shí)戰(zhàn)

本文主要從以下幾個(gè)方面介紹PostgreSQL高可用集群在360的落地實(shí)戰(zhàn)

背景介紹

為什么選擇Patroni + Etcd + PostgreSQL高可用集群方案

Patroni + Etcd 高可用集群架構(gòu)解析

Patroni + Etcd + PostgreSQL 部署實(shí)戰(zhàn)

Patroni 日常運(yùn)維管理

PostgreSQL 監(jiān)控實(shí)現(xiàn)

PostgreSQL 應(yīng)用連接方式

PostgreSQL 備份恢復(fù)方式選擇


背景

? ? 最近線上重要業(yè)務(wù)容器云的鏡像倉(cāng)庫(kù)需要部署一套postgresql 高可用集群,涉及到數(shù)據(jù)庫(kù)選型,最終選擇了postgresql,為什么不選擇mysql呢,postgresql是功能最強(qiáng)大的開(kāi)源數(shù)據(jù)庫(kù),主要考慮pg 支持使用函數(shù)索引和條件索引,text 沒(méi)有限制,可以索引,還可以全文檢索,不用再接一套es,并且postgresql 開(kāi)源協(xié)議好,開(kāi)源軟件原生支持好,特別對(duì)開(kāi)發(fā)來(lái)說(shuō)比較友好,最重要的是kube-bench 只支持postgresql??


為什么選擇Patroni + Etcd 方案

PostgreSQL 比較流行的高可用解決方案有很多,常用的主要包含repmgr和patroni等,也是github star前幾的高可用組件,并且文檔更新比較及時(shí),都可最高支持postgresql 13,repmgr 相對(duì)來(lái)說(shuō)功能沒(méi)有patroni全面以及不能檢測(cè)備機(jī)是否被錯(cuò)誤配置為未知或不存在的節(jié)點(diǎn)、不能檢測(cè)遠(yuǎn)程節(jié)點(diǎn)的狀態(tài)(不具備分布式解決方案)和不能處理單個(gè)節(jié)點(diǎn)的恢復(fù),本文主要基于patroni 實(shí)現(xiàn)。

此方案使用Patroni管理本地庫(kù),并結(jié)合Etcd作為數(shù)據(jù)存儲(chǔ)和主節(jié)點(diǎn)選舉,具有以下優(yōu)勢(shì)

o健壯性: 使用分布式key-value數(shù)據(jù)庫(kù)作為數(shù)據(jù)存儲(chǔ),主節(jié)點(diǎn)故障時(shí)進(jìn)行主節(jié)點(diǎn)重新選舉,具有很強(qiáng)的健壯性

o支持多種復(fù)制方式: 基于內(nèi)置流復(fù)制,支持同步流復(fù)制、異步流復(fù)制、級(jí)聯(lián)復(fù)制

o支持主備延遲設(shè)置: 可以設(shè)置備庫(kù)延遲主庫(kù)WAL的字節(jié)數(shù),當(dāng)備庫(kù)延遲大于指定值時(shí)不做故障切換

o自動(dòng)化程度高:

①支持自動(dòng)化初始PostgreSQL實(shí)例并部署流復(fù)制

②當(dāng)備庫(kù)實(shí)例關(guān)閉后,支持自動(dòng)拉起

③當(dāng)主庫(kù)實(shí)例關(guān)閉后,首先會(huì)嘗試自動(dòng)拉起

④支持switchover命令,能自動(dòng)將老的主庫(kù)進(jìn)行角色轉(zhuǎn)換? ? ?

o避免腦裂: 數(shù)據(jù)庫(kù)信息記錄到 ETCD 中,通過(guò)優(yōu)化部署策略(多機(jī)房部署、增加實(shí)例數(shù))可以避免腦裂

Patroni + Etcd 高可用架構(gòu)

Patroni 是一個(gè)開(kāi)源工具套件,它是用 Python編寫(xiě)的,可確保 PostgreSQL HA 集群的端到端設(shè)置,包括流復(fù)制。它的功能通過(guò)REST API顯示,也通過(guò)一個(gè)名為 Patronictl 的命令行實(shí)用程序顯示。它通過(guò)使用其運(yùn)行狀況檢查API來(lái)處理負(fù)載平衡來(lái)支持與 HAProxy 的集成。在此 HA 解決方案中,etcd 用于分布式配置存儲(chǔ) (DCS),以實(shí)現(xiàn)最大的可訪問(wèn)性,下面是官方高可用集群方案的架構(gòu)圖展示,我們基于此完成postgresql 高可用架構(gòu)集群方案設(shè)計(jì),不過(guò)并沒(méi)有使用HAproxy 進(jìn)行負(fù)載均衡,而是使用公司內(nèi)部的LVS 來(lái)實(shí)現(xiàn)的,一主兩副本,副本部署在不同的idc 實(shí)現(xiàn)異地災(zāi)備,etcd 也是三節(jié)點(diǎn)集群分別部署在三臺(tái)機(jī)器, 如果資源有限,也可以和postgresql/patroni部署在相同機(jī)器



Etcd、Patroni 和PostgreSQL是如何一起工作的

etcd/patroni/postgresql 都是部署的3節(jié)點(diǎn)集群

Etcd: 分布式的Key-Value數(shù)據(jù)庫(kù)

etcd1、etcd2、 etcd3作為分布式的Key-Value數(shù)據(jù)庫(kù),被partroni1、 patroni2、 patroni3讀/寫(xiě),用于共享/傳遞信息。每一個(gè) Patroni都能讀/寫(xiě)etcd中的數(shù)據(jù).

Paroni: 控制/監(jiān)控本地的PostgreSQL, 把本地PostgreSQL信息/狀態(tài)寫(xiě)入etcd

每一個(gè) Patroni實(shí)例監(jiān)控/控制本地的PostgreSQL,把本地本地PostgreSQL信息/狀態(tài)寫(xiě)入etcd , 一個(gè)Patroni實(shí)例能夠通過(guò)讀取etcd獲取外地PostgreSQL的信息/狀態(tài).

PostreSQL主節(jié)點(diǎn)的選舉

Patroni判斷本地PostgreSQL是否可以作為Primary庫(kù)。如果可以,Paroni試圖選舉本地PostgreSQL作為Primary(Leader) , 選舉方式是:把etcd中的某個(gè)key更新成為本地PostgreSQL的名字, 如果多個(gè)Paroni同時(shí)更改同一個(gè)key,只有一個(gè)能改成功,然后成為Primary(Leader)。

部署篇

系統(tǒng)/軟件/版本

?CentOS 7.4

?PostgreSQL 12.6

?etcd: 3.2.18

?python: Python 3.6.5

?Patroni: 2.1.0

主機(jī)信息

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臺(tái)機(jī)器,也可以用3臺(tái)機(jī)器組件全部安裝在一起

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運(yùn)行環(huán)境到虛擬環(huán)境

source venv4archery/bin/activate

創(chuàng)建PG目錄和用戶

useradd postgres #編譯安裝的,yum 安裝不用創(chuàng)建

mkdir -p /data04/pg15432

mkdir -p /data04/pg15432/data

mkdir -p /data04/pg15432/scripts

chown -R postgres:postgres /data04/pg15432/

創(chuàng)建歸檔目錄

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 配置文件

Etcd node1配置

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_NAME="node1"

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_NAME="node2"

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_NAME="node3"

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 每個(gè)節(jié)點(diǎn)都不一樣,etcd-cluster-1 是集群名字統(tǒng)一

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/

#啟動(dòng)patroni集群需非root用戶

集群進(jìn)行初始化(所有節(jié)點(diǎn)執(zhí)行)

patroni /etc/patroni.yml? > patroni_member_1.log 2>&1 &

可以使用centos7的service啟動(dòng):

[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 (可根據(jù)自己需求定制化)

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

? ? ? ? ? ? ? ? Shared_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

重點(diǎn)關(guān)注上面標(biāo)紅的參數(shù)設(shè)置,如果初始化未設(shè)置也沒(méi)關(guān)系,部署完成一定驗(yàn)證下重要參數(shù)設(shè)置,未設(shè)置的可以通過(guò)patronictl 進(jìn)行設(shè)置

PG集群信息查看



數(shù)據(jù)庫(kù)賬戶創(chuàng)建

CREATE USER docker WITH PASSWORD 'xxxx';

CREATE DATABASE docker OWNER docker;?

GRANT ALL PRIVILEGES ON DATABASE docker to docker;

遠(yuǎn)程連接數(shù)據(jù)庫(kù)

psql -U docker -d docker -p xxxx-h xxxx

嘗試對(duì)主節(jié)點(diǎn)進(jìn)行讀寫(xiě)


以上完成對(duì)整個(gè)集群的部署并確保數(shù)據(jù)庫(kù)可以正常進(jìn)行讀寫(xiě)

Patronictl 日常運(yùn)維

參數(shù)設(shè)置查看

shared_buffers

類(lèi)似mysql innodb_buffer_pool_size,該參數(shù)主要設(shè)置數(shù)據(jù)庫(kù)服務(wù)器將使用的共享內(nèi)存緩沖區(qū)量,建議是設(shè)置系統(tǒng)內(nèi)存的25%,過(guò)高也會(huì)造成一些工作負(fù)載,還是需要跟業(yè)務(wù)溝通獲取預(yù)估的數(shù)據(jù)量以及估算熱數(shù)據(jù)量來(lái)針對(duì)性制定參數(shù)值

修改shared_buffers

patronictl -c /etc/patroni.yml edit-config -p "shared_buffers='32GB'"


patronictl -c /etc/patroni.yml restart postgresql (重啟生效)

max_connections

? 決定數(shù)據(jù)庫(kù)的最大并發(fā)連接數(shù)。默認(rèn)值通常是 100 個(gè)連接,但是如果內(nèi)核設(shè)置不支持(initdb時(shí)決定),可能會(huì)比這個(gè) 數(shù)少。這個(gè)參數(shù)只能在服務(wù)器啟動(dòng)時(shí)設(shè)置。

當(dāng)運(yùn)行一個(gè)后備服務(wù)器時(shí),你必須設(shè)置這個(gè)參數(shù)等于或大于主服務(wù)器上的參數(shù)。否則,后備服務(wù)器上可能無(wú)法允許查詢

修改max_connections

patronictl -c /etc/patroni.yml edit-config -p 'max_connections=6000'


patronictl -c /etc/patroni.yml restart postgresql (重啟生效)


查看當(dāng)前歸檔日志

select pg_walfile_name(pg_current_wal_lsn());



手動(dòng)切換歸檔

select pg_walfile_name(pg_current_wal_lsn());


可以看到歸檔已經(jīng)由...0000B 切換到...0000C

設(shè)置開(kāi)啟慢日志

閾值為200ms

patronictl -c /etc/patroni.yml edit-config -p 'log_min_duration_statement=200'?



查看慢日志設(shè)置閾值



高可用故障轉(zhuǎn)移測(cè)試

Kill 主節(jié)點(diǎn)進(jìn)程


會(huì)發(fā)現(xiàn)patroni 會(huì)自動(dòng)拉起postgresql進(jìn)程,并且還是主節(jié)點(diǎn),并未進(jìn)行切主

手工切主

假設(shè)切主到postgresql2 155節(jié)點(diǎn)

patronictl -d etcd://10.16.75.17:2379 switchover postgresql


切主期間會(huì)出現(xiàn)中間狀態(tài)unknown,瞬間會(huì)恢復(fù)正常如下,切主成功到155


重啟集群



可看到主節(jié)點(diǎn)也是沒(méi)切主,拓?fù)浜鸵郧笆且粯拥?/p>

主/從節(jié)點(diǎn)機(jī)器重啟

機(jī)器宕機(jī)是常有的事情,當(dāng)postgresql 某個(gè)節(jié)點(diǎn)所在機(jī)器宕機(jī)恢復(fù)后,需要手動(dòng)拉起節(jié)點(diǎn)

patroni /etc/patroni.yml? > patroni_member_1.log 2>&1 &

禁用開(kāi)啟故障轉(zhuǎn)移

當(dāng)pause 后,這時(shí)候集群是不會(huì)進(jìn)行自動(dòng)故障轉(zhuǎn)移的,可以在某些特定場(chǎng)景使用,然后用resume 恢復(fù)就可以了




還有其它一些功能可以參考patronictl --help

PostgreSQL監(jiān)控

監(jiān)控是眼睛,對(duì)于運(yùn)維來(lái)說(shuō)非常重要,這邊主要采用的是Grafana + Prometheus 監(jiān)控PostgreSQL,自帶PG監(jiān)控指標(biāo)模版,也可自己定制詳盡指標(biāo),結(jié)合內(nèi)部告警平臺(tái)編寫(xiě)api 實(shí)現(xiàn)告警短信發(fā)送以及推推內(nèi)部溝通軟件推送,具體部署這里就不詳細(xì)闡述了,監(jiān)控界面如下:







監(jiān)控參考:

https://www.bbsmax.com/A/pRdBKG0Pzn/

dashboard json 下載模版

https://grafana.com/grafana/dashboards?search=postgresql&orderBy=reviewsCount&direction=desc

下載好json 文件直接在dashboard倒入模版即可

監(jiān)控指標(biāo)rules 可自己定制,可選擇常用的,比較重要的指標(biāo)即可

應(yīng)用連接方式

? 這邊采用的是公司內(nèi)部的lvs機(jī)制,通過(guò)掛載vip的方式來(lái)實(shí)現(xiàn)讀寫(xiě)分離,也可以通過(guò)haproxy 等組件來(lái)實(shí)現(xiàn)負(fù)載均衡,多一層組件就會(huì)多一層故障點(diǎn),同樣需要保證高可用,可根據(jù)業(yè)務(wù)重要程度進(jìn)行抉擇



PostgreSQL 備份


PostgreSQL流復(fù)制備份可選擇物理備份或者邏輯備份,邏輯備份可選擇pg_dump 進(jìn)行單表備份或者pg_dumpall進(jìn)行全庫(kù)備份,物理備份可選擇pg_basebackup 或者pg_rman 備份,在此我選擇pg_rman 進(jìn)行備份,下面重點(diǎn)介紹下強(qiáng)大的pg_rman 備份工具

pg_rman是一個(gè)開(kāi)源的PostgreSQL備份管理軟件,類(lèi)似Oracle的RMAN,使用的是pg_start_backup(), copy, pg_stop_backup()的備份模式,pg_rman跑的不是流復(fù)制協(xié)議,而是文件拷貝,所以pg_rman必須和數(shù)據(jù)庫(kù)節(jié)點(diǎn)跑在一起,如果在standby節(jié)點(diǎn)運(yùn)行pg_rman,pg_rman則需要通過(guò)網(wǎng)絡(luò)連接到主節(jié)點(diǎn)執(zhí)行pg_start_backup/pg_stop_backup

pg_rman可支持的主要功能如下:

◎全量備份

◎增量備份

◎檢驗(yàn)備份集

◎列出備份集

◎按指定時(shí)間從catalog 刪除備份集

◎物理刪除已從catalog刪除的備份集

相信用過(guò)oracle的同學(xué)了解oracle rman 備份的強(qiáng)大就清楚pg_rman 的功能強(qiáng)大之處,具體可參考http://mysql.taobao.org/monthly/2016/09/05/


未來(lái)展望:

????PostgreSQL?在最新的數(shù)據(jù)庫(kù)DB-Engines?9月榜單高居第四,是功能最強(qiáng)大的開(kāi)源數(shù)據(jù)庫(kù),增勢(shì)迅速,穩(wěn)定性極強(qiáng),特別是在GIS領(lǐng)域處于優(yōu)勢(shì)地位,有豐富統(tǒng)計(jì)函數(shù)和統(tǒng)計(jì)語(yǔ)法支持對(duì)開(kāi)發(fā)特別友好,而且高可用復(fù)制架構(gòu)越來(lái)越完善,相信在不久的將來(lái)在國(guó)內(nèi)應(yīng)用會(huì)越來(lái)越廣泛

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容