openGauss+KeepAlived

openGaussbaby發表於2024-04-17

openGauss+KeepAlived
實驗環境
作業系統: CentOS 7.6

資料庫版本: openGauss 1.1.0Primary

主機/IP: opengaussdb1/...1 (openGauss 主備已部署完畢)

Standby 主機/IP: opengaussdb2/...2 (openGauss 主備已部署完畢)

說明:

不建議在雲環境(如:華為雲)下搭建 Keepalived 進行測試,本人在雲環境下測試發現,Keepalived 的 VIP 無法在雲環境下與其他主機通訊,雲環境下如何使用該 VIP 建議諮詢雲服務廠商。在踩坑之後,選擇使用本地的 VMWare workstation 進行簡單測試。

安裝 KeepAlived 軟體

在所有節點執行安裝

yum install keepalived -y
配置 keepalived
說明:

採用 nopreempt 不搶佔 VIP,主備節點的 state 均設定為 BACKUP。

主節點配置檔案。

vi /etc/keepalived/keepalived.conf


! Configuration File for keepalived

全域性定義

global_defs {
router_id Keepalived_openGauss #執行 keepalived 伺服器的一個標識
script_user root #執行指令碼的使用者
}

VRRP例項定義

通常如果master服務Down掉後backup會變成master,但是當master服務又好了的時候 master此時會搶佔VIP,這樣就會發生兩次資料庫切換。

建議使用nopreempt引數設定為非搶佔模式,此時主庫從故障中恢復後,不會從新的主庫搶回VIP,但這需要將master和backup的state都設定成backup。

vrrp_instance VI_1 {
state BACKUP #指定Keepalived的角色(BACKUP需大寫)
interface eth0 #指定 HA 監測的網路介面
virtual_router_id 59 #虛擬路由的數字標識,同一個 vrrp_instance 下,MASTER 和 BACKUP 一致
nopreempt #非搶佔模式,主庫從故障中恢復後,不會從新的主庫搶回VIP
priority 100 #優先順序,備節點需要適當降低優先順序
advert_int 1 #MASTER 和 BACKUP 負載均衡器同步檢查的時間間隔(秒)
authentication { #設定驗證碼和驗證型別
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { #設定虛擬 IP 地址,可以設定多個,每個一行
...0
}
}

虛擬伺服器定義

virtual_server ...0 26000 { #設定虛擬伺服器的 IP 和埠,用空格隔開
delay_loop 6 #設定執行情況檢查時間,單位是秒

lb_algo rr #負載排程演算法(輪詢)

lb_kind DR #負載均衡機制(NAT、TUN、DR)

persistence_timeout 50 #會話保持時間(秒)
protocol TCP #轉發協議型別
real_server ...1 26000 { #配置服務節點
weight 100 #配置服務節點的權重
notify_down /gauss/failoverdb.sh #故障響應指令碼
TCP_CHECK { #使用TCP_CHECK方式進行健康檢查
connect_timeout 10 #10秒無響應即超時
delay_before_retry 3 #重試間隔時間
}
}
}
主節點故障切換指令碼(僅適用 openGauss 程序崩潰故障處理,不適用 Primary 作業系統當機故障處理)。
vi /gauss/failoverdb.sh

!/bin/bash

echo "Start to failover openGauss database."
pkill keepalived
ssh ...2 "su - omm -c 'gs_ctl failover -D /gauss/data/db1'"
ssh ...2 "su - omm -c 'gs_om -t refreshconf'"
echo 'Failover operation is completed.'

chmod 764 /gauss/failoverdb.sh
備節點配置檔案。

vi /etc/keepalived/keepalived.conf


! Configuration File for keepalived

全域性定義

global_defs {
router_id Keepalived_openGauss #執行 keepalived 伺服器的一個標識
script_user root #執行指令碼的使用者
}

VRRP例項定義

通常如果master服務Down掉後backup會變成master,但是當master服務又好了的時候 master此時會搶佔VIP,這樣就會發生兩次資料庫切換。

建議使用nopreempt引數設定為非搶佔模式,此時主庫從故障中恢復後,不會從新的主庫搶回VIP,但這需要將master和backup的state都設定成backup。

vrrp_instance VI_1 {
state BACKUP #指定Keepalived的角色(BACKUP需大寫)
interface eth0 #指定 HA 監測的網路介面
virtual_router_id 59 #虛擬路由的數字標識,同一個 vrrp_instance 下,MASTER 和 BACKUP 一致
nopreempt #非搶佔模式,主庫從故障中恢復後,不會從新的主庫搶回VIP
priority 60 #優先順序,備節點需要適當降低優先順序
advert_int 1 #MASTER 和 BACKUP 負載均衡器同步檢查的時間間隔(秒)
authentication { #設定驗證碼和驗證型別
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { #設定虛擬 IP 地址,可以設定多個,每個一行
...0
}
}

虛擬伺服器定義

virtual_server ...0 26000 { #設定虛擬伺服器的 IP 和埠,用空格隔開
delay_loop 6 #設定執行情況檢查時間,單位是秒

lb_algo rr #負載排程演算法(輪詢)

lb_kind DR #負載均衡機制(NAT、TUN、DR)

persistence_timeout 50 #會話保持時間(秒)
protocol TCP #轉發協議型別
real_server ...2 26000 { #配置服務節點
weight 60 #配置服務節點的權重
notify_down /gauss/failoverdb.sh #虛擬服務故障響應指令碼
MISC_CHECK { ## 使用 MISC_CHECK 方式自定義指令碼做健康檢查
misc_path "/gauss/check.sh" ## 檢測指令碼
misc_timeout 10 ## 執行指令碼的超時時間
misc_dynamic ## 根據退出狀態碼動態調整伺服器的權重
}
}
}

備節點選擇MISC_CHECK方式的原因:

測試發現,當主節點直接斷電當機後,Keepalived的VIP會漂移至備節點,此時如果使用TCP_CHECK方式做健康檢查,會因為備機可讀的原因使得VIP:26000連線正常,造成keepalived健康檢查的誤判。

最終導致主節點斷電當機後,備節點雖獲取了VIP,但並沒有執行openGauss的failover操作,備節點依舊只讀,無法對外提供業務。

為了糾正這一點,建議使用MISC_CHECK方式自定義指令碼,登入主節點做資料庫健康檢查(簡單示例指令碼:/gauss/check.sh)

備節點健康檢查指令碼[ ssh 登入主節點進行資料庫連線檢查 ]。
vi /gauss/check.sh

ssh ...1 "su - omm -c "gsql -d postgres -p 26000 -t -A -c 'select 1;'""

備節點故障切換指令碼。
vi /gauss/failoverdb.sh

!/bin/bash

echo "Start to failover openGauss database."
pkill keepalived
su - omm -c "gs_ctl failover -D /gauss/data/db1"
su - omm -c "gs_om -t refreshconf"
echo 'Failover operation is completed.'

chmod 764 /gauss/failoverdb.sh
openGauss 配置
修改 openGauss 偵聽地址。
$ gs_guc set -I all -N all -c "listen_addresses = '...'"
$ gs_guc set -I all -N all -c "local_bind_address = '...'"
修改所有節點 replconninfo 引數(避免埠衝突)。
$ vi /gauss/data/db1/postgresql.conf

修改:localport --> 26011
修改:remoteport --> 26011

重啟 openGauss 資料庫,並檢查伺服器狀態。

重啟openGauss

[omm@prod db1]$ gs_om -t stop && gs_om -t start

檢查openGauss狀態

[root@opengaussdb1 ~]# su - omm -c "gs_om -t status --detail"
[ Cluster State ]
cluster_state : Normal
redistributing : No
current_az : AZ_ALL
[ Datanode State ]

node node_ip instance state
1 opengaussdb1 ...1 6001 /gauss/data/db1 P Primary Normal
2 opengaussdb2 ...2 6002 /gauss/data/db1 S Standby Normal

檢查KeepAlived程序狀態

[omm@opengaussdb1 ~]$ ps -ef|grep keep|grep -v grep
root 15664 1 0 16:15 ? 00:00:00 /usr/sbin/keepalived -D
root 15665 15664 0 16:15 ? 00:00:00 /usr/sbin/keepalived -D
root 15666 15664 0 16:15 ? 00:00:00 /usr/sbin/keepalived -D

檢查VIP狀態

[root@opengaussdb1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet .../8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:da:60:c0 brd ff:ff:ff:ff:ff:ff
inet ...1/24 brd ... scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet ...0/32 scope global ens33 ## VIP:...0
valid_lft forever preferred_lft forever
inet6 2408:8270:237:ded0:c89c:adab:e7b:8bd6/64 scope global noprefixroute dynamic
valid_lft 258806sec preferred_lft 172406sec
inet6 fe80::c4f2:8ad1:200d:ce9b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
故障模擬測試
主節點[...1]操作。

kill資料庫程序

[root@opengaussdb1 ~]# ps -ef|grep gauss
omm 18115 1 4 16:30 ? 00:00:35 /gauss/app/bin/gaussdb -D /gauss/data/db1 -M primary
root 19254 9299 0 16:42 pts/0 00:00:00 grep --color=auto gauss
[root@opengaussdb1 ~]# kill -9 18115

檢查message日誌[檢測到故障,執行notify_down指令碼,並關閉keepalived服務]

tail -fn 200 /var/log/messages

Feb 19 16:42:57 opengaussdb1 Keepalived_healthcheckers[18816]: TCP connection to [...1]:26000 failed.
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: TCP connection to [...1]:26000 failed.
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: Check on service [...1]:26000 failed after 1 retry.
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: Removing service [...1]:26000 from VS [...0]:26000
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: IPVS (cmd 1160, errno 2): No such destination
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: Executing [/gauss/failoverdb.sh] for service [...1]:26000 in VS [...0]:26000
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: Lost quorum 1-0=1 > 0 for VS [...0]:26000
Feb 19 16:43:00 opengaussdb1 Keepalived[18815]: Stopping
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: pid 19258 exited due to signal 15
Feb 19 16:43:00 opengaussdb1 Keepalived_vrrp[18817]: VRRP_Instance(VI_1) sent 0 priority
Feb 19 16:43:00 opengaussdb1 Keepalived_vrrp[18817]: VRRP_Instance(VI_1) removing protocol VIPs.
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: IPVS (cmd 1156, errno 2): No such file or directory
Feb 19 16:43:00 opengaussdb1 Keepalived_healthcheckers[18816]: Stopped
Feb 19 16:43:01 opengaussdb1 Keepalived_vrrp[18817]: Stopped
Feb 19 16:43:01 opengaussdb1 Keepalived[18815]: Stopped Keepalived v1.3.5 (03/19,2017), git commit v1.3.5-6-g6fa32f2
備節點[...2]檢查。

檢查VIP是否已漂移

[root@opengaussdb2 ~]# ip a|grep 192.168
inet ...2/24 brd ... scope global noprefixroute ens33
inet ...0/32 scope global ens33

檢查資料庫狀態[已failover成為Primary]

[omm@opengaussdb2 ~]$ gs_om -t status --detail
[ Cluster State ]
cluster_state : Degraded
redistributing : No
current_az : AZ_ALL
[ Datanode State ]

node node_ip instance state
1 opengaussdb1 ...1 6001 /gauss/data/db1 P Down Manually stopped
2 opengaussdb2 ...2 6002 /gauss/data/db1 S Primary Normal