最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Keepalived實(shí)現(xiàn)集群高可用全過程

 更新時(shí)間:2026年02月24日 09:28:07   作者:feng68_  
文章描述了三種高可用架構(gòu)的實(shí)現(xiàn):LVS DR模式、Nginx/HAProxy高可用方案以及數(shù)據(jù)庫高可用性,每種方案都詳細(xì)描述了環(huán)境架構(gòu)、實(shí)踐步驟和關(guān)鍵配置,以確保系統(tǒng)的高可用性和可靠性

1 場(chǎng)景1:Keepalived + LVS

1.1.1 環(huán)境

直接用之前做的LVS的DR模式了,加個(gè)VSNode即可。

LVS(linuxvirtualserver)

主機(jī)名角色IP地址VIP網(wǎng)關(guān)VRRP狀態(tài)
Router路由器172.25.254.100/192.168.0.100NULL172.25.254.2NULL
VSNode1LVS Director (KA1)192.168.0.50192.168.0.200(keepalived管理VIP浮動(dòng))192.168.0.100MASTER (priority 100)
VSNode2LVS Director (KA2)192.168.0.60192.168.0.200(keepalived管理VIP浮動(dòng))192.168.0.100BACKUP (priority 80)
RS1Real Server192.168.0.20192.168.0.200(lo)192.168.0.100NULL
RS2Real Server192.168.0.30192.168.0.200(lo)192.168.0.100NULL
Client測(cè)試機(jī)172.25.254.101NULL可以抵達(dá)Router都可NULL
 # Router
 [root@Router ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
 [root@Router ~]# sysctl -p
 net.ipv4.ip_forward = 1
 [root@Router ~]# ip addr | egrep "eth0$|eth1$"
     inet 172.25.254.100/24 brd 172.25.254.255 scope global noprefixroute eth0
     inet 192.168.0.100/24 brd 192.168.0.255 scope global noprefixroute eth1
 # VS50
 [root@VSNode50 ~]# ip addr | grep "eth0$"
     inet 192.168.0.50/24 brd 192.168.0.255 scope global noprefixroute eth0
 [root@VSNode50 ~]# route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
 192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
 # VS60
 [root@VSNode60 ~]# ip addr | grep "eth0$"
     inet 192.168.0.60/24 brd 192.168.0.255 scope global noprefixroute eth0
 [root@VSNode60 ~]# route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
 192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
 # RS20
 [root@RS20 ~]# ip a | egrep "lo$|eth0"
     inet 127.0.0.1/8 scope host lo
     inet 192.168.0.200/32 scope global lo
 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
     inet 192.168.0.20/24 brd 192.168.0.255 scope global noprefixroute eth0
 [root@RS20 ~]# route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
 192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
 # RS30
 [root@RS30 ~]# ip a | egrep "lo$|eth0"
     inet 127.0.0.1/8 scope host lo
     inet 192.168.0.200/32 scope global lo
 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
     inet 192.168.0.30/24 brd 192.168.0.255 scope global noprefixroute eth0
 [root@RS30 ~]# route -n
 Kernel IP routing table
 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
 0.0.0.0         192.168.0.100   0.0.0.0         UG    100    0        0 eth0
 192.168.0.0     0.0.0.0         255.255.255.0   U     100    0        0 eth0
 # 防止RS響應(yīng)VIP的ARP請(qǐng)求,避免VIP沖突(永久生效-->改/etc/sysctl.conf文件)
 [root@RS20 ~]# cat >> /etc/sysctl.conf << 'EOF'
 > net.ipv4.conf.all.arp_ignore = 1
 > net.ipv4.conf.all.arp_announce = 2
 > net.ipv4.conf.lo.arp_ignore = 1
 > net.ipv4.conf.lo.arp_announce = 2
 > EOF
 [root@RS20 ~]# sysctl -p
 net.ipv4.conf.all.arp_ignore = 1
 net.ipv4.conf.all.arp_announce = 2
 net.ipv4.conf.lo.arp_ignore = 1
 net.ipv4.conf.lo.arp_announce = 2
 [root@RS20 ~]# sysctl net.ipv4.conf.all.arp_ignore
 net.ipv4.conf.all.arp_ignore = 1
 [root@RS20 ~]# sysctl net.ipv4.conf.all.arp_announce
 net.ipv4.conf.all.arp_announce = 2
 [root@RS30 ~]# cat >> /etc/sysctl.conf << 'EOF'
 > net.ipv4.conf.all.arp_ignore = 1
 > net.ipv4.conf.all.arp_announce = 2
 > net.ipv4.conf.lo.arp_ignore = 1
 > net.ipv4.conf.lo.arp_announce = 2
 > EOF
 [root@RS30 ~]# sysctl -p
 net.ipv4.conf.all.arp_ignore = 1
 net.ipv4.conf.all.arp_announce = 2
 net.ipv4.conf.lo.arp_ignore = 1
 net.ipv4.conf.lo.arp_announce = 2
 [root@RS30 ~]# sysctl net.ipv4.conf.all.arp_ignore
 net.ipv4.conf.all.arp_ignore = 1
 [root@RS30 ~]# sysctl net.ipv4.conf.all.arp_announce
 net.ipv4.conf.all.arp_announce = 2

ARP參數(shù):

參數(shù)含義
arp_ignore = 1只響應(yīng)目的IP是本地接口的ARP請(qǐng)求避免lo上的VIP響應(yīng)ARP
arp_announce = 2始終使用最佳本地地址發(fā)送ARP避免宣告VIP的MAC地址
 [root@VSNode50 ~]# dnf install -y keepalived ipvsadm >/dev/null
 [root@VSNode60 ~]# dnf install -y keepalived ipvsadm >/dev/null
 [root@RS20 ~]# dnf install httpd -y >/dev/null
 [root@RS20 ~]# echo RS20 - 192.168.0.20 > /var/www/html/index.html
 [root@RS20 ~]# systemctl enable --now httpd
 [root@RS30 ~]# dnf install httpd -y >/dev/null
 [root@RS30 ~]#  echo RS30 - 192.168.0.30 > /var/www/html/index.html
 [root@RS30 ~]# systemctl enable --now httpd

1.1.2 實(shí)踐

Router火墻規(guī)則

 [root@Router ~]# iptables -t nat -F
 [root@Router ~]# iptables -t nat -L
 Chain PREROUTING (policy ACCEPT)
 target     prot opt source               destination
 ?
 Chain INPUT (policy ACCEPT)
 target     prot opt source               destination
 ?
 Chain OUTPUT (policy ACCEPT)
 target     prot opt source               destination
 ?
 Chain POSTROUTING (policy ACCEPT)
 target     prot opt source               destination
 [root@Router ~]# iptables -t nat -A PREROUTING -d 172.25.254.100 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.200:80
 [root@Router ~]# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to-source 172.25.254.100
 [root@Router ~]# iptables -t nat -L -n -v
 Chain PREROUTING (policy ACCEPT 1 packets, 108 bytes)
  pkts bytes target     prot opt in     out     source               destination
     0     0 DNAT       6    --  *      *       0.0.0.0/0            172.25.254.100       tcp dpt:80 to:192.168.0.200:80
 Chain POSTROUTING (policy ACCEPT 1 packets, 76 bytes)
  pkts bytes target     prot opt in     out     source               destination
     0     0 SNAT       0    --  *      eth0    192.168.0.0/24       0.0.0.0/0            to:172.25.254.100
 [root@Router ~]# dnf install -y iptables-services > /dev/null
 [root@Router ~]# iptables-save > /etc/sysconfig/iptables
 [root@Router ~]# systemctl enable --now iptables.service

VS

 # keepalive
 [root@VSNode50 ~]# vim /etc/keepalived/keepalived.conf
   1 ! Configuration File for keepalived
   2
   3 global_defs {
   4    notification_email {
   5      acassen@firewall.loc
   6      failover@firewall.loc
   7      sysadmin@firewall.loc
   8    }
   9    notification_email_from Alexandre.Cassen@firewall.loc
  10    smtp_server 192.168.200.1
  11    smtp_connect_timeout 30
  12    router_id VS50
  13    vrrp_skip_check_adv_addr
  14    #vrrp_strict     # 必須注釋掉,否則會(huì)添加iptables規(guī)則阻斷轉(zhuǎn)發(fā)
  15    vrrp_garp_interval 0
  16    vrrp_gna_interval 0
  17 }
  18
  19 # VRRP實(shí)例:實(shí)現(xiàn)Director高可用
  20 vrrp_instance VI_1 {
  21     state MASTER
  22     interface eth0
  23     virtual_router_id 51
  24     priority 100
  25     advert_int 1
  26     authentication {
  27         auth_type PASS
  28         auth_pass 1111
  29     }
  30     virtual_ipaddress {
  31         192.168.0.200/32 dev eth0 label eth0:0
  32     }
  33 }
  34 # LVS虛擬服務(wù)器配置(核心)
  35 virtual_server 192.168.0.200 80 {
  36     delay_loop 6                      # 健康檢查間隔(秒)
  37     lb_algo rr                        # 負(fù)載均衡算法:rr=輪詢,wrr=加權(quán)輪詢
  38     lb_kind DR                        # LVS模式:DR=直接路由(性能最佳)
  39     protocol TCP                      # 協(xié)議類型
  40
  41     # 后端真實(shí)服務(wù)器 RS1
  42     real_server 192.168.0.20 80 {
  43         weight 1                    # 權(quán)重(rr算法下無效,wrr時(shí)生效)
  44         TCP_CHECK {                 # TCP健康檢查
  45             connect_timeout 3       # 連接超時(shí)(秒)
  46             nb_get_retry 3          # 重試次數(shù)
  47             delay_before_retry 3    # 重試間隔(秒)
  48         }
  49     }
  50
  51     # 后端真實(shí)服務(wù)器 RS2
  52     real_server 192.168.0.30 80 {
  53         weight 1
  54         TCP_CHECK {
  55             connect_timeout 3
  56             nb_get_retry 3
  57             delay_before_retry 3
  58         }
  59     }
  60 }
 [root@VSNode50 ~]# scp /etc/keepalived/keepalived.conf root@192.168.0.60:/etc/keepalived/keepalived.conf
 Warning: Permanently added '192.168.0.60' (ED25519) to the list of known hosts.
 keepalived.conf                                                                   100% 1578     3.1MB/s   00:00
 [root@VSNode50 ~]# systemctl enable --now keepalived.service
 [root@VSNode60 ~]# vim /etc/keepalived/keepalived.conf
 # VS60
 ?
   1 ! Configuration File for keepalived
   2
   3 global_defs {
 ………………
  12    router_id VS60
  13    vrrp_skip_check_adv_addr
  14    #vrrp_strict
 ………………
  17 }
  19 # VRRP實(shí)例:實(shí)現(xiàn)Director高可用
  20 vrrp_instance VI_1 {
  21     state BACKUP
 ………………
  24     priority 80
 ………………
  33 }
 # LVS配置與VSNode1完全相同
 [root@VSNode60 ~]# systemctl enable --now keepalived.service
 ?
 # 查看LVS規(guī)則
 [root@VSNode60 ~]# ipvsadm -Ln
 IP Virtual Server version 1.2.1 (size=4096)
 Prot LocalAddress:Port Scheduler Flags
   -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
 TCP  192.168.0.200:80 rr
   -> 192.168.0.20:80              Route   1      0          0
   -> 192.168.0.30:80              Route   1      0          0

測(cè)試

 [root@VSNode50 ~]# ip a | grep eth0:0
     inet 192.168.0.200/32 scope global eth0:0
 [root@Client ~]# for i in {1..4};do curl 172.25.254.100;done
 RS30 - 192.168.0.30
 RS20 - 192.168.0.20
 RS30 - 192.168.0.30
 RS20 - 192.168.0.20
 [root@VSNode50 ~]# ipvsadm -Ln --stats
 IP Virtual Server version 1.2.1 (size=4096)
 Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
   -> RemoteAddress:Port
 TCP  192.168.0.200:80                    4       24        0     1592        0
   -> 192.168.0.20:80                     2       12        0      796        0
   -> 192.168.0.30:80                     2       12        0      796        0
 [root@VSNode60 ~]# ipvsadm -Ln --stats
 IP Virtual Server version 1.2.1 (size=4096)
 Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
   -> RemoteAddress:Port
 TCP  192.168.0.200:80                    0        0        0        0        0
   -> 192.168.0.20:80                     0        0        0        0        0
   -> 192.168.0.30:80                     0        0        0        0        0
 [root@VSNode50 ~]# systemctl stop keepalived.service
 [root@Client ~]# for i in {1..4};do curl 172.25.254.100;done
 RS30 - 192.168.0.30
 RS20 - 192.168.0.20
 RS30 - 192.168.0.30
 RS20 - 192.168.0.20
 [root@VSNode60 ~]# ip a | grep eth0:0
     inet 192.168.0.200/32 scope global eth0:0
 [root@VSNode60 ~]# ipvsadm -Ln --stats
 IP Virtual Server version 1.2.1 (size=4096)
 Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
   -> RemoteAddress:Port
 TCP  192.168.0.200:80                    4       24        0     1592        0
   -> 192.168.0.20:80                     2       12        0      796        0
   -> 192.168.0.30:80                     2       12        0      796        0

2 場(chǎng)景2:Keepalived + Nginx/HAProxy

2.1 Keepalived+Nginx方案

2.1.1 環(huán)境

架構(gòu)設(shè)計(jì)

環(huán)境信息
節(jié)點(diǎn)IP地址角色VRRP實(shí)例
KA1172.25.254.50Nginx + KeepalivedWEB_VIP: MASTER, DB_VIP: BACKUP
KA2172.25.254.60Nginx + KeepalivedWEB_VIP: BACKUP, DB_VIP: MASTER
RS1172.25.254.20后端Web服務(wù)器NULL
RS2172.25.254.30后端Web服務(wù)器NULL
VIP1172.25.254.100Web服務(wù)入口主: KA1, 備: KA2
VIP2172.25.254.200備用入口(或DB服務(wù))主: KA2, 備: KA1

2.2.2 實(shí)踐

RS測(cè)試頁
 [root@RS1 ~]# dnf install nginx -y > /dev/null
 [root@RS1 ~]# echo "RS1 - 172.25.254.20" > /usr/share/nginx/html/index.html
 [root@RS2 ~]# echo "RS2 - 172.25.254.30" > /usr/share/nginx/html/index.html
 [root@RS2 ~]# systemctl enable --now nginx.service
 [2026-02-22 15:29.09]  ~
 [Is XiaFeng Computer.IsXiaFengComputer] ? curl 172.25.254.20
 RS1 - 172.25.254.20
 [2026-02-22 15:29.15]  ~
 [Is XiaFeng Computer.IsXiaFengComputer] ? curl 172.25.254.30
 RS2 - 172.25.254.30
KA實(shí)現(xiàn)高可用
KA1
 # KA配置Nginx反向代理
 [root@KA1 ~]# dnf install nginx -y > /dev/null
 [root@KA1 ~]# vim /etc/nginx/conf.d/upstream.conf
   1 upstream backend {
   2     server 172.25.254.20:80 weight=5;
   3     server 172.25.254.30:80 weight=5;
   4     keepalive 32;  # 長連接
   5 }
   6 server {
   7     listen 80;
   8     server_name localhost;
   9     location / {
  10         proxy_pass http://backend;
  11         proxy_set_header Host $host;
  12         proxy_set_header X-Real-IP $remote_addr;
  13         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  14         proxy_connect_timeout 5s;
  15         proxy_send_timeout 5s;
  16         proxy_read_timeout 5s;
  17     }
  18     # 健康檢查端點(diǎn)(用于Keepalived檢測(cè))
  19     location /health {
  20         access_log off;
  21         return 200 "healthy\n";
  22         add_header Content-Type text/plain;
  23     }
  24 }
 # 采用雙主模式為基礎(chǔ)
 # 創(chuàng)建 health 檢查頁
 [root@KA1 ~]# mkdir /usr/share/nginx/html/health
 [root@KA1 ~]# echo "OK" > /usr/share/nginx/html/health/health.html
 # 健康檢查腳本
 [root@KA1 ~]# vim /etc/keepalived/check_nginx.sh
   1 #!/bin/bash
   3 # 檢查Nginx進(jìn)程
   4 if ! pgrep -x "nginx" > /dev/null; then
   5     # 嘗試啟動(dòng)Nginx
   6     systemctl start nginx
   7     sleep 2
   8     # 再次檢查
   9     if ! pgrep -x "nginx" > /dev/null; then
  10         # Nginx啟動(dòng)失敗,返回錯(cuò)誤觸發(fā)切換
  11         exit 1
  12     fi
  13 fi
  15 # 檢查Nginx端口是否監(jiān)聽
  16 if ! ss -tlnp | grep -q ":80"; then
  17     exit 1
  18 fi
  20 # 可選:檢查HTTP響應(yīng)
  21 if ! curl -sf http://localhost/health > /dev/null; then
  22      exit 1
  23 fi
  24 exit 0
 [root@KA1 ~]# chmod +x /etc/keepalived/check_nginx.sh
 [root@KA1 ~]# nginx -t && systemctl enable --now nginx
 [root@KA1 ~]# /etc/keepalived/check_nginx.sh && echo "Check OK" || echo "Check FAILED"
 Check OK
 # 通知腳本
 [root@KA1 ~]# systemctl is-active postfix.service
 inactive
 [root@KA1 ~]# systemctl start postfix.service
 [root@KA1 ~]# chmod +x /etc/keepalived/notify_nginx.sh
   1 #!/bin/bash
   2 mail_dest='收件人'
   3 TYPE=$1          # WEB_VIP 或 DB_VIP
   4 STATE=$2         # MASTER, BACKUP, FAULT
   5 LOG_FILE="/var/log/keepalived/notify.log"
   6 mkdir -p $(dirname $LOG_FILE)
   7 echo "$(date '+%Y-%m-%d %H:%M:%S') - Instance: $TYPE, State: $STATE, Host: $(hostname)" >> $LOG_FILE
   8 case $STATE in
   9     MASTER)
  10         # 成為Master時(shí)的額外操作
  11         echo "$(date) - Becoming MASTER for $TYPE" >> $LOG_FILE
  12         # 可以在這里添加告警通知
  13         ;;
  14     BACKUP)
  15         echo "$(date) - Becoming BACKUP for $TYPE" >> $LOG_FILE
  16         ;;
  17     FAULT)
  18         echo "$(date) - FAULT state for $TYPE" >> $LOG_FILE
  19         # 發(fā)送緊急告警
  20         ;;
  21 esac
 # KA1中keepalived設(shè)置
 [root@KA1 ~]# vim /etc/keepalived/keepalived.conf
   3 global_defs {
 ………………
  18    enable_script_security   # 啟用腳本執(zhí)行權(quán)限
  19    script_user root root    # 指定專用用戶,因?yàn)樗胁渴鸲际怯胷oot用戶去部署的
  20 }
  21
  22 # Nginx健康檢查腳本
  23 vrrp_script check_nginx {
  24     script "/etc/keepalived/check_nginx.sh"
  25     interval 2          # 每2秒檢查一次
  26     weight -20          # 檢查失敗,優(yōu)先級(jí)降低20
  27     fall 2              # 連續(xù)2次失敗才判定失敗
  28     rise 1              # 1次成功恢復(fù)
  29 }
  30
  31 vrrp_instance WEB_VIP {
  32     state MASTER
  33     interface eth0
  34     virtual_router_id 51
  35     priority 100
  36     advert_int 1
  37     authentication {
  38         auth_type PASS
  39         auth_pass 1111
  40     }
  41     virtual_ipaddress {
  42         172.25.254.100/24 dev eth0 label eth0:1
  43     }
  44     # 追蹤健康檢查腳本
  45     track_script {
  46         check_nginx
  47     }
  48     # 狀態(tài)切換通知
  49     notify_master "/etc/keepalived/notify_nginx.sh WEB_VIP MASTER"
  50     notify_backup "/etc/keepalived/notify_nginx.sh WEB_VIP BACKUP"
  51     notify_fault "/etc/keepalived/notify_nginx.sh WEB_VIP FAULT"
  52 }
  53
  54 vrrp_instance DB_VIP {
  55     state BACKUP
  56     interface eth0
  57     virtual_router_id 52
  58     priority 80
  59     advert_int 1
  60     authentication {
  61         auth_type PASS
  62         auth_pass 1111
  63     }
  64     virtual_ipaddress {
  65         172.25.254.200/24 dev eth0 label eth0:0
  66     }
  67         track_script {
  68         check_nginx
  69     }
  70     notify_master "/etc/keepalived/notify_nginx.sh DB_VIP MASTER"
  71     notify_backup "/etc/keepalived/notify_nginx.sh DB_VIP BACKUP"
  72     notify_fault "/etc/keepalived/notify_nginx.sh DB_VIP FAULT"
  73 }
 [root@KA1 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
 SECURITY VIOLATION - scripts are being executed but script_security not enabled.
 ?
 [root@KA2 ~]# mkdir /usr/share/nginx/html/health
 ?
 [root@KA1 ~]# scp /etc/nginx/conf.d/upstream.conf root@172.25.254.60:/etc/nginx/conf.d/upstream.conf
 upstream.conf                                                   100%  672     1.5MB/s   00:00
 [root@KA1 ~]# scp /etc/keepalived/check_nginx.sh root@172.25.254.60:/etc/keepalived/
 check_nginx.sh                                                                         100%  469   978.8KB/s   00:00
 [root@KA1 ~]# scp /usr/share/nginx/html/health/health.html root@172.25.254.60:/usr/share/nginx/html/health/
 health.html                                                                            100%    3     5.6KB/s   00:00
 [root@KA1 ~]# scp /etc/keepalived/notify_nginx.sh root@172.25.254.60:/etc/keepalived/
 notify_nginx.sh                                                               100%  654     1.1MB/s   00:00
KA2
 # KA2:
 [root@KA2 ~]# dnf install nginx -y > /dev/null
 [root@KA2 ~]# ll /etc/nginx/conf.d/upstream.conf /etc/keepalived/check_nginx.sh /usr/share/nginx/html/health/health.html /etc/keepalived/notify_nginx.sh
 -rwxr-xr-x 1 root root 469 Feb 22 16:19 /etc/keepalived/check_nginx.sh
 -rwxr-xr-x 1 root root 654 Feb 22 16:27 /etc/keepalived/notify_nginx.sh
 -rw-r--r-- 1 root root 672 Feb 22 15:34 /etc/nginx/conf.d/upstream.conf
 -rw-r--r-- 1 root root   3 Feb 22 16:20 /usr/share/nginx/html/health/health.html
 [root@KA2 ~]# nginx -t && systemctl enable --now nginx
 [root@KA2 ~]# systemctl is-active postfix.service
 inactive
 [root@KA2 ~]# systemctl start postfix.service
 [root@KA2 ~]# /etc/keepalived/check_nginx.sh && echo "Check OK" || echo "Check FAILED"
 Check OK
 ?
 # KA2中keepalived設(shè)置
 [root@KA2 ~]# vim /etc/keepalived/keepalived.conf
   3 global_defs {
 ………………    
  17    enable_script_security  # 啟用腳本執(zhí)行權(quán)限
  18    script_user root root    # 指定專用用戶,因?yàn)樗胁渴鸲际怯胷oot用戶去部署的
  19 }
  20 # Nginx健康檢查腳本
  21 vrrp_script check_nginx {
  22     script "/etc/keepalived/check_nginx.sh"
  23     interval 2
  24     weight -20
  25     fall 2
  26     rise 1
  27 }
  28
  29 vrrp_instance WEB_VIP {
  30     state BACKUP
  31     interface eth0
  32     virtual_router_id 51
  33     preempt_delay 10        # 搶占延遲10秒(避免網(wǎng)絡(luò)抖動(dòng))
  34     priority 80
  35     advert_int 1
  36     authentication {
  37         auth_type PASS
  38         auth_pass 1111
  39     }
  40     virtual_ipaddress {
  41         172.25.254.100/24 dev eth0 label eth0:1
  42     }
  43     track_script {
  44         check_nginx
  45     }
  46     notify_master "/etc/keepalived/notify_nginx.sh WEB_VIP MASTER"
  47     notify_backup "/etc/keepalived/notify_nginx.sh WEB_VIP BACKUP"
  48     notify_fault "/etc/keepalived/notify_nginx.sh WEB_VIP FAULT"
  49 }
  50
  51 vrrp_instance DB_VIP {
  52     state MASTER
  53     interface eth0
  54     virtual_router_id 52
  55     preempt_delay 10
  56     priority 100
  57     advert_int 1
  58     authentication {
  59         auth_type PASS
  60         auth_pass 1111
  61     }
  62     virtual_ipaddress {
  63         172.25.254.200/24 dev eth0 label eth0:0
  64     }
  65     track_script {
  66         check_nginx
  67     }
  68     notify_master "/etc/keepalived/notify_nginx.sh DB_VIP MASTER"
  69     notify_backup "/etc/keepalived/notify_nginx.sh DB_VIP BACKUP"
  70     notify_fault "/etc/keepalived/notify_nginx.sh DB_VIP FAULT"
  71 }
 [root@KA2 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
 (DB_VIP) Warning - preempt delay will not work with initial state MASTER - clearing
測(cè)試
 # 測(cè)試
 [root@KA1 ~]# systemctl is-active keepalived.service
 active
 [root@KA1 ~]# systemctl reload keepalived.service
 [root@KA2 ~]# systemctl reload keepalived.service
 [root@KA1 ~]# ip a s | grep eth0:1$
     inet 172.25.254.100/24 scope global secondary eth0:1
 [root@KA2 ~]# ip a s | grep eth0:0$
     inet 172.25.254.200/24 scope global secondary eth0:0

global_defs { enable_script_security # 啟用腳本執(zhí)行權(quán)限 script_user root root # 指定專用用戶,因?yàn)樗胁渴鸲际怯胷oot用戶去部署的 }

現(xiàn)實(shí)中都是為所有軟件創(chuàng)建對(duì)應(yīng)的用戶和用戶組,具體操作和注意點(diǎn)看大數(shù)據(jù)筆記,這里為了方便就只能root用戶實(shí)踐。

2.2 keepalive+HAProxy

基于Keepalived+Nginx改動(dòng)

2.2.1 環(huán)境

架構(gòu)設(shè)計(jì)

環(huán)境信息
節(jié)點(diǎn)IP地址角色VRRP實(shí)例
KA1172.25.254.50HAProxy + KeepalivedWEB_VIP: MASTER, API_VIP: BACKUP
KA2172.25.254.60HAProxy + KeepalivedWEB_VIP: BACKUP, API_VIP: MASTER
RS1172.25.254.20后端Web/API服務(wù)器NULL
RS2172.25.254.30后端Web/API服務(wù)器NULL

2.2.2 實(shí)踐

RS
 [root@RS1 ~]# mkdir -p /usr/share/nginx/html/api
 [root@RS1 ~]# echo '{"status":"ok","server":"RS1","ip":"172.25.254.20"}' > /usr/share/nginx/html/api/status.json
 [root@RS1 ~]# vim /etc/nginx/conf.d/default.conf
 [root@RS1 ~]# nginx -t && nginx -s reload
 [root@RS1 ~]# curl http://172.25.254.20
 RS1 - 172.25.254.20
 [root@RS1 ~]# curl http://172.25.254.20/api/status.json
 {"status":"ok","server":"RS1","ip":"172.25.254.20"}
 [root@RS1 ~]# curl http://172.25.254.20/health
 healthy
 [root@RS1 ~]# scp /etc/nginx/conf.d/default.conf root@172.25.254.30:/etc/nginx/conf.d/
 default.conf                                                               100%  502   928.3KB/s   00:00
 ?
 [root@RS2 ~]# mkdir -p /usr/share/nginx/html/api
 [root@RS2 ~]# echo '{"status":"ok","server":"RS2","ip":"172.25.254.30"}' > /usr/share/nginx/html/api/status.json
 [root@RS2 ~]# nginx -t && nginx -s reload
KA實(shí)現(xiàn)高可用性
 [root@KA1 ~]# systemctl stop keepalived.service     # 由于上個(gè)實(shí)驗(yàn)做了nginx健康保護(hù),直接stop的話Nginx會(huì)被其他進(jìn)程守護(hù)自動(dòng)重啟,或者說不能及時(shí)關(guān)閉,先把keepalived停后才可以,也說明有看門狗機(jī)制在保護(hù)它。
 [root@KA1 ~]# systemctl disable --now nginx
 [root@KA1 ~]# netstat -lntupa | grep nginx
 [root@KA1 ~]# systemctl is-active nginx
 inactive
 [root@KA1 ~]# dnf install haproxy -y > /dev/null
 [root@KA1 ~]# systemctl enable --now haproxy
 ?
 [root@KA2 ~]# systemctl stop keepalived.service
 [root@KA2 ~]# systemctl disable --now nginx
 [root@KA2 ~]# netstat -lntupa | grep nginx
 [root@KA2 ~]# systemctl is-active nginx
 inactive
 [root@KA2 ~]# dnf install haproxy -y > /dev/null
 [root@KA2 ~]# systemctl enable --now haproxy
KA1
 # HAProxy設(shè)定:KA1與KA2一致
 [root@KA1 ~]# vim /etc/haproxy/haproxy.cfg
  64 # 統(tǒng)計(jì)頁面
  65 listen stats
  66     bind *:8080
  67     stats enable
  68     stats uri /stats
  69     stats auth admin:admin123
  70     stats refresh 30s
  71
  72 # Web服務(wù)前端(對(duì)應(yīng)VIP1 172.25.254.100)
  73 frontend web_frontend
  74     bind *:80
  75     acl is_api path_beg /api
  76     use_backend api_servers if is_api
  77     default_backend web_servers
  78
  79 # Web服務(wù)后端(/health 使用 Nginx return 指令)
  80 backend web_servers
  81     balance roundrobin
  82     option httpchk GET /health
  83     http-check expect status 200
  84     server rs1 172.25.254.20:80 check weight 5 inter 2s rise 2 fall 3
  85     server rs2 172.25.254.30:80 check weight 5 inter 2s rise 2 fall 3
  86
  87 # API服務(wù)后端(/api/status.json 物理文件)
  88 backend api_servers
  89     balance roundrobin
  90     option httpchk GET /api/status.json
  91     http-check expect status 200
  92     server rs1 172.25.254.20:80 check weight 5 inter 2s rise 2 fall 3
  93     server rs2 172.25.254.30:80 check weight 5 inter 2s rise 2 fall 3
 # HAProxy 健康檢查腳本(KA1和KA2相同)
 [root@KA1 ~]# vim /etc/keepalived/check_haproxy.sh
   1 #!/bin/bash
   2 # 檢查HAProxy進(jìn)程
   3 if ! pgrep -x "haproxy" > /dev/null; then
   4     systemctl start haproxy
   5     sleep 2
   6     if ! pgrep -x "haproxy" > /dev/null; then
   7         exit 1
   8     fi
   9 fi
  10 # 檢查HAProxy端口(80和8080統(tǒng)計(jì)頁面)
  11 if ! ss -tlnp | grep -q ":80"; then
  12     exit 1
  13 fi
  14 exit 0
 [root@KA1 ~]# chmod +x /etc/keepalived/check_haproxy.sh
 [root@KA1 ~]# /etc/keepalived/check_haproxy.sh && echo "HAProxy OK" || echo "HAProxy FAILED"
 [root@KA1 ~]# /etc/keepalived/check_haproxy.sh && echo "HAProxy OK" || echo "HAProxy FAILED"
 HAProxy OK
 # 通知告警腳本
 [root@KA1 ~]# cp /etc/keepalived/notify_nginx.sh /etc/keepalived/notify_haproxy.sh
 [root@KA1 ~]# scp /etc/keepalived/notify_haproxy.sh root@172.25.254.60:/etc/keepalived/
 notify_haproxy.sh                                                                                   100%  684   564.8KB/s   00:00
 ?
 [root@KA1 ~]# scp /etc/haproxy/haproxy.cfg root@172.25.254.60:/etc/haproxy/haproxy.cfg
 haproxy.cfg                                                                                100% 4220     4.7MB/s   00:00
 [root@KA1 ~]# scp /etc/keepalived/check_haproxy.sh root@172.25.254.60:/etc/keepalived/
 check_haproxy.sh                                                                           100%  293   465.5KB/s   00:00
 ?
 # KA1 Keepalived配置,基于Keepalived + Nginx雙主模式
 [root@KA1 ~]# vim /etc/keepalived/keepalived.conf
  22 # HAProxy健康檢查腳本
  23 vrrp_script check_haproxy {
  24     script "/etc/keepalived/check_haproxy.sh"
  25     interval 2          # 每2秒檢查一次
  26     weight -20          # 檢查失敗,優(yōu)先級(jí)降低20
  27     fall 2              # 連續(xù)2次失敗才判定失敗
  28     rise 1              # 1次成功恢復(fù)
  29 }
  31 # VIP1: Web服務(wù)入口,KA1為主
  32 vrrp_instance WEB_VIP {
 ………………
  45     track_script {
  46         check_haproxy
  47     }
  48     notify_master "/etc/keepalived/notify_haproxy.sh WEB_VIP MASTER"
  49     notify_backup "/etc/keepalived/notify_haproxy.sh WEB_VIP BACKUP"
  50     notify_fault "/etc/keepalived/notify_haproxy.sh WEB_VIP FAULT"
  51 }
  52
  53 # VIP2: API服務(wù)入口,KA1為備
  54 vrrp_instance API_VIP {
 ………………
  70     notify_master "/etc/keepalived/notify_haproxy.sh WEB_VIP MASTER"
  71     notify_backup "/etc/keepalived/notify_haproxy.sh WEB_VIP BACKUP"
  72     notify_fault "/etc/keepalived/notify_haproxy.sh WEB_VIP FAULT"
  73 }
 [root@KA1 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
KA2
 [root@KA2 ~]# systemctl reload haproxy.service
 [root@KA2 ~]# /etc/keepalived/check_haproxy.sh && echo "HAProxy OK" || echo "HAProxy FAILED"
 HAProxy OK
 ?
 # KA2 Keepalived配置,基于Keepalived + Nginx雙主模式
 [root@KA2 ~]# vim /etc/keepalived/keepalived.conf
  31 # VIP1: Web服務(wù)入口,KA2為備
  32 vrrp_instance WEB_VIP {
 ………………
  46     track_script {
  47         check_haproxy
  48     }
  49     notify_master "/etc/keepalived/notify_haproxy.sh WEB_VIP MASTER"
  50     notify_backup "/etc/keepalived/notify_haproxy.sh WEB_VIP BACKUP"
  51     notify_fault "/etc/keepalived/notify_haproxy.sh WEB_VIP FAULT"
  52 }
  54
  55 # VIP2: API服務(wù)入口,KA2為主
  56 vrrp_instance API_VIP {
 ………………
  70     track_script {
  71         check_haproxy
  72     }
  73     notify_master "/etc/keepalived/notify_haproxy.sh API_VIP MASTER"
  74     notify_backup "/etc/keepalived/notify_haproxy.sh API_VIP BACKUP"
  75     notify_fault "/etc/keepalived/notify_haproxy.sh API_VIP FAULT"
  76 }
 [root@KA2 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
 (API_VIP) Warning - preempt delay will not work with initial state MASTER - clearing
測(cè)試
[root@KA1 ~]# systemctl start keepalived.service
[root@KA2 ~]# systemctl start keepalived.service
# 雙主狀態(tài)驗(yàn)證
[root@KA1 ~]# ip a s | grep eth0:1$
    inet 172.25.254.100/24 scope global secondary eth0:1
[root@KA2 ~]# ip a s | grep eth0:0$
    inet 172.25.254.200/24 scope global secondary eth0:0
# 服務(wù)訪問測(cè)試
[root@Client ~]# for i in {1..4};do curl 172.25.254.100;done
RS1 - 172.25.254.20
RS2 - 172.25.254.30
RS1 - 172.25.254.20
RS2 - 172.25.254.30
[root@Client ~]# for i in {1..4};do curl http://172.25.254.200/api/status.json;done
{"status":"ok","server":"RS1","ip":"172.25.254.20"}
{"status":"ok","server":"RS2","ip":"172.25.254.30"}
{"status":"ok","server":"RS1","ip":"172.25.254.20"}
{"status":"ok","server":"RS2","ip":"172.25.254.30"}
[root@Client ~]# curl http://172.25.254.100/health
healthy

3 場(chǎng)景3:數(shù)據(jù)庫高可用

3.1.1 環(huán)境

架構(gòu)設(shè)計(jì)

核心原則:數(shù)據(jù)庫必須單主

原則說明
單 VIP只有一個(gè)入口,確保寫操作唯一性
單 Master任何時(shí)候只有一個(gè)節(jié)點(diǎn)接受寫操作
自動(dòng)檢測(cè)Keepalived 檢測(cè) MySQL 狀態(tài),故障時(shí) VIP 漂移
手動(dòng)/半自動(dòng)切換主從切換需要謹(jǐn)慎,建議配合 MHA 或手動(dòng)

環(huán)境信息

節(jié)點(diǎn)IP地址角色說明
KA1172.25.254.50Keepalived BACKUPVIP 故障時(shí)接管
KA2172.25.254.60Keepalived MASTER正常時(shí)持有 VIP
DB1172.25.254.40MySQL Master主庫,接受讀寫
DB2172.25.254.41MySQL Slave從庫,只讀/熱備
VIP172.25.254.200數(shù)據(jù)庫入口指向當(dāng)前 Master

3.2.2 實(shí)踐

DB主從復(fù)制

DB1
# DB1:
[root@RS1 ~]# systemctl stop nginx.service
[root@RS1 ~]# dnf install mysql-server -y >/dev/null
[root@RS1 ~]# vim /etc/my.cnf
 11 [mysqld]
 12 server-id = 20
 13 # GTID 復(fù)制(推薦)
 14 gtid_mode = ON
 15 enforce_gtid_consistency = ON
 16 log-bin = mysql-bin
 17 binlog-format = ROW
 18 expire_logs_days = 7
 19 max_binlog_size = 100M
 20 # 半同步復(fù)制(可選但推薦)
 21 plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
 22 rpl-semi-sync-master-enabled = 1
 23 rpl-semi-sync-slave-enabled = 1
 24 rpl-semi-sync-master-timeout = 1000
 25 # 字符集
 26 character-set-server = utf8mb4
 27 # 綁定所有接口
 28 bind-address = 0.0.0.0
 29 # 為 Keepalived 檢測(cè)預(yù)留的用戶
 30 skip-name-resolve
[root@RS1 ~]# systemctl enable --now mysqld
[root@RS1 ~]# mysql
# 創(chuàng)建復(fù)制用戶
mysql> create user 'repl'@'172.25.254.%' identified with mysql_native_password by '123';
mysql> grant replication slave on *.* to 'repl'@'172.25.254.%';
# 創(chuàng)建健康檢查用戶(用于 Keepalived 檢測(cè))
mysql> create user 'check'@'172.25.254.%' identified with mysql_native_password by '123';
mysql> grant process,replication client,show databases on *.* to 'check'@'172.25.254.%';
mysql> flush privileges;
mysql> show master status;
+---------------+----------+--------------+------------------+-------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000001 |     1237 |              |                  |                   |
+---------------+----------+--------------+------------------+-------------------+
mysql> SHOW VARIABLES LIKE 'gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| gtid_executed                    |           |
| gtid_executed_compression_period | 0         |
| gtid_mode                        | ON        |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
+----------------------------------+-----------+
# 數(shù)據(jù)庫剛啟動(dòng),還沒有執(zhí)行任何寫入操作,沒有產(chǎn)生事務(wù),gtid_executed為空的原因。
mysql> create database test_gtid;
mysql> use test_gtid;
Database changed
mysql> create table t1 (id int primary key, name varchar(50));
mysql> insert into t1 values (1,'test');
mysql> SHOW VARIABLES LIKE 'gtid_executed';
+---------------+------------------------------------------+
| Variable_name | Value                                    |
+---------------+------------------------------------------+
| gtid_executed | b650e3a0-102f-11f1-9134-000c29999103:1-3 |
+---------------+------------------------------------------+
DB2
# DB2:
[root@RS2 ~]# systemctl stop nginx.service
[root@RS2 ~]# dnf install mysql-server -y >/dev/null
[root@RS2 ~]# vim /etc/my.cnf
 10 !includedir /etc/my.cnf.d
 11 [mysqld]
 12 server-id = 30
 13 # GTID
 14 gtid_mode = ON
 15 enforce_gtid_consistency = ON
 16 log-bin = mysql-bin
 17 binlog-format = ROW
 18 expire_logs_days = 7
 19 # 半同步復(fù)制,起不來,后面想辦法加上去。
 20 # plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
 21 # rpl-semi-sync-master-enabled = 1
 22 # rpl-semi-sync-slave-enabled = 1
 23 # 只讀(重要!防止誤寫入)
 24 read_only = 1
 25 super_read_only = 1
 26 character-set-server = utf8mb4
 27 bind-address = 0.0.0.0
 28 skip-name-resolve
[root@RS2 ~]# systemctl enable --now mysqld
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
# 關(guān)閉只讀
mysql> set global super_read_only = OFF;
mysql> set global read_only = OFF;
# 安裝插件
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
# 啟用插件
mysql> set global rpl_semi_sync_master_enabled = ON;
mysql> set global rpl_semi_sync_slave_enabled = ON;
# 創(chuàng)建復(fù)制用戶
mysql> create user 'repl'@'172.25.254.%' identified with mysql_native_password by '123';
mysql> grant replication slave on *.* to 'repl'@'172.25.254.%';
# 創(chuàng)建健康檢查用戶(用于 Keepalived 檢測(cè))
mysql> create user 'check'@'172.25.254.%' identified with mysql_native_password by '123';
mysql> grant process,replication client,show databases on *.* to 'check'@'172.25.254.%';
# 重新開啟只讀(從庫必須保持只讀)
mysql> set global read_only = ON;
# 查看插件狀態(tài)
mysql> show plugins;
………………	# 正常
# 查看變量
mysql> show variables like 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 10000      |
| rpl_semi_sync_master_trace_level          | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
| rpl_semi_sync_slave_enabled               | ON         |
| rpl_semi_sync_slave_trace_level           | 32         |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)
# 配置主從復(fù)制
mysql> change master to
    -> master_host = '172.25.254.20',
    -> master_port = 3306,
    -> master_user = 'repl',
    -> master_password = '123',
    -> master_auto_position = 1,	# GTID 自動(dòng)定位
    -> master_connect_retry = 10;
mysql> start slave;
mysql> show slave status\G
*************************** 1. row ***************************
…………
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
…………
測(cè)試
[root@RS1 ~]# mysql
mysql> create database test_haha;
mysql> use test_haha
mysql> create table t1 (id int primary key,name varchar(50));
mysql> insert into t1 values (1,'from Master DB1');
[root@RS2 ~]# mysql -e "SELECT * FROM test_haha.t1;"
+----+-----------------+
| id | name            |
+----+-----------------+
|  1 | from Master DB1 |
+----+-----------------+

KA實(shí)現(xiàn)高可用

# 安裝 MySQL 客戶端用于檢測(cè)
[root@KA1 ~]# systemctl stop keepalived.service
[root@KA1 ~]# systemctl stop haproxy.service
[root@KA1 ~]# dnf install mysql -y >/dev/null
[root@KA2 ~]# dnf install mysql -y >/dev/null
[root@KA1 ~]# mysql -h172.25.254.30 -ucheck -p123 -e "SELECT 1;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---+
| 1 |
+---+
| 1 |
+---+
[root@KA1 ~]# mysql -h172.25.254.20 -ucheck -p123 -e "SELECT 1;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---+
| 1 |
+---+
| 1 |
+---+
KA1
# MySQL 檢查腳本
[root@KA1 ~]# vim /etc/keepalived/check_mysql.sh
  1 #!/bin/bash
  2
  3 # MySQL 檢測(cè)腳本
  4 # 檢測(cè)遠(yuǎn)程 MySQL 是否可連接且為主庫(read_only=OFF)
  5
  6 MYSQL_HOST="172.25.254.20"      # 當(dāng)前主庫 IP
  7 MYSQL_USER="check"
  8 MYSQL_PASS="123"
  9 MYSQL_PORT=3306
 10 LOG_FILE="/var/log/keepalived_mysql_check.log"
 11 # 記錄檢測(cè)時(shí)間
 12 echo "$(date '+%Y-%m-%d %H:%M:%S') - Checking MySQL at $MYSQL_HOST" >> $LOG_FILE
 13 # 檢測(cè)1:MySQL 是否可連接
 14 if ! mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT -e "SELECT 1;" > /dev/null 2>&1; then
 15     echo "$(date): MySQL $MYSQL_HOST connection FAILED" >> $LOG_FILE
 16     exit 1
 17 fi
 18 # 檢測(cè)2:是否為 Master(read_only = OFF)
 19 READ_ONLY=$(mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT -e "SHOW VARIABLES LIKE 'read_only';" 2>/dev/null | grep read_only     | awk '{print $2}')
 20 if [ "$READ_ONLY" = "ON" ]; then
 21     echo "$(date): MySQL $MYSQL_HOST is read_only, not master" >> $LOG_FILE
 22     exit 1
 23 fi
 24 # 檢測(cè)3:復(fù)制延遲檢測(cè)
 25 SLAVE_LAG=$(mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep Seconds_Behind_Master |     awk '{print $2}')
 26 if [ "$SLAVE_LAG" != "NULL" ] && [ "$SLAVE_LAG" -gt 60 ]; then
 27     echo "$(date): Replication lag $SLAVE_LAG seconds" >> $LOG_FILE
 28     exit 1
 29 fi
 30 echo "$(date): MySQL $MYSQL_HOST check PASSED" >> $LOG_FILE
 31 exit 0
[root@KA1 ~]# chmod +x /etc/keepalived/check_mysql.sh
[root@KA1 ~]# /etc/keepalived/check_mysql.sh && echo "MySQL OK" || echo "MySQL FAILED"
/etc/keepalived/check_mysql.sh: line 26: [: : integer expression expected
MySQL OK

# 切換腳本(Master故障時(shí)自動(dòng)切換主從)
[root@KA1 ~]# vim /etc/keepalived/notify_mysql.sh
  1 #!/bin/bash
  2
  3 TYPE=$1         # DB_VIP
  4 STATE=$2        # MASTER, BACKUP, FAULT
  5 CURRENT_HOST=$(hostname)
  6 LOG_FILE="/var/log/keepalived_mysql.log"
  7 mkdir -p $(dirname $LOG_FILE)
  8 echo "$(date '+%Y-%m-%d %H:%M:%S') - $TYPE on $CURRENT_HOST changed to $STATE" >> $LOG_FILE
  9 case $STATE in
 10     MASTER)
 11         echo "$(date): !!! This node is now MASTER for MySQL VIP !!!" >> $LOG_FILE
 12         echo "$(date): VIP 172.25.254.200 is now on $CURRENT_HOST" >> $LOG_FILE
 13         # 重要:發(fā)送告警通知管理員
 14         echo "MySQL VIP failover occurred at $(date)" | \
 15             mail -s "CRITICAL: MySQL HA Failover" xiafeng_68@163.com 2>/dev/null || true
 16         # 注意:這里不做自動(dòng)主從切換!
 17         # 原因:1. 腦裂風(fēng)險(xiǎn) 2. 數(shù)據(jù)一致性風(fēng)險(xiǎn)
 18         # 建議:人工確認(rèn)后手動(dòng)執(zhí)行切換腳本
 19         # 自動(dòng)提升DB2為主(風(fēng)險(xiǎn)高,需謹(jǐn)慎)
 20         # mysql -h172.25.254.30 -ugxf -p123 -e "STOP SLAVE; RESET SLAVE ALL; SET GLOBAL read_only = 0;"
 21
 22         echo "$(date): ACTION REQUIRED: Please verify and execute manual failover if needed" >> $LOG_FILE
 23         ;;
 24
 25     BACKUP)
 26         echo "$(date): This node is now BACKUP for MySQL VIP" >> $LOG_FILE
 27         ;;
 28
 29     FAULT)
 30         echo "$(date): FAULT state detected on $CURRENT_HOST" >> $LOG_FILE
 31         ;;
 32 esac
[root@KA1 ~]# chmod +x /etc/keepalived/notify_mysql.sh
# 手動(dòng)主從切換腳本(故障時(shí)使用)
[root@KA1 ~]# vim /etc/keepalived/manual_failover.sh
  1 #!/bin/bash
  2
  3 # 當(dāng) DB1 故障時(shí),在確認(rèn)后手動(dòng)執(zhí)行此腳本將 DB2 提升為yy主庫
  4 NEW_MASTER="172.25.254.30"      # DB2
  5 OLD_MASTER="172.25.254.20"      # DB1
  6 VIP="172.25.254.200"
  7 echo "=== MySQL 手動(dòng)故障切換 ==="
  8 echo "時(shí)間: $(date)"
  9 echo "新主庫: $NEW_MASTER (DB2)"
 10 echo "舊主庫: $OLD_MASTER (DB1) - 假設(shè)已故障"
 11 # 1. 在 DB2 上停止復(fù)制并提升為主庫
 12 echo "步驟1: 在 DB2 上停止復(fù)制..."
 13 mysql -h$NEW_MASTER -ugxf -p123 -e "
 14     STOP SLAVE;
 15     RESET SLAVE ALL;
 16     SET GLOBAL read_only = OFF;
 17     SET GLOBAL super_read_only = OFF;
 18     SELECT 'DB2 is now MASTER' as status;
 19 "
 20 # 2. 更新 KA 的檢測(cè)腳本指向新主庫
 21 echo "步驟2: 更新 Keepalived 檢測(cè)腳本..."
 22 sed -i "s/MYSQL_HOST=\"$OLD_MASTER\"/MYSQL_HOST=\"$NEW_MASTER\"/" /etc/keepalived/check_mysql.sh
 23 # 3. 如果舊主庫恢復(fù),需要重新配置為從庫(可選)
 24 echo "步驟3: 當(dāng)舊主庫恢復(fù)后,執(zhí)行以下命令重新加入:"
 25 echo "  CHANGE MASTER TO MASTER_HOST='$NEW_MASTER', MASTER_USER='repl', MASTER_PASSWORD='Repl123', MASTER_AUTO_POSITION=1;"
 26 echo "  START SLAVE;"
 27 echo "切換完成!VIP $VIP 現(xiàn)在指向新主庫 $NEW_MASTER"
[root@KA1 ~]# chmod +x /etc/keepalived/manual_failover.sh
[root@KA1 ~]# scp /etc/keepalived/manual_failover.sh root@172.25.254.60:/etc/keepalived/
manual_failover.sh                                                                          100% 1175   736.0KB/s   00:00
[root@KA1 ~]# scp /etc/keepalived/check_mysql.sh root@172.25.254.60:/etc/keepalived/
check_mysql.sh                                                                                                 100% 1309     1.6MB/s   00:00
[root@KA1 ~]# scp /etc/keepalived/notify_mysql.sh root@172.25.254.60:/etc/keepalived/
notify_mysql.sh                                                                                                           100% 1323     2.6MB/s   00:00

# KA1配置keepalived
  1 ! Configuration File for keepalived
  2
  3 global_defs {
………………
 13    vrrp_skip_check_adv_addr
 14    #vrrp_strict				# 必須關(guān)閉,否則阻斷MySQL連接
………………
 18    enable_script_security   # 啟用腳本執(zhí)行權(quán)限
 19    script_user root root    # 指定專用用戶,因?yàn)樗胁渴鸲际怯胷oot用戶去部署的
 20 }
 21
 22 # MySql健康檢查腳本
 23 vrrp_script check_mysql {
 24     script "/etc/keepalived/check_mysql.sh"
 25     interval 3          # MySQL檢測(cè)間隔稍長
 26     weight -20          # 檢查失敗,優(yōu)先級(jí)降低20
 27     fall 2              # 連續(xù)2次失敗才判定失敗
 28     rise 2              # 連續(xù)2次成功恢復(fù)
 29 }
 30
 31 # 單VIP:數(shù)據(jù)庫入口
 32 vrrp_instance DB_VIP {
 33     state BACKUP        # KA1作為BACKUP
 34     interface eth0
 35     virtual_router_id 52
 36     priority 80         # 低于KA2
 37     advert_int 1
 38     authentication {
 39         auth_type PASS
 40         auth_pass 2222
 41     }
 42     virtual_ipaddress {
 43         172.25.254.200/24 dev eth0 label eth0:0
 44     }
 45     track_script {
 46         check_mysql
 47     }
 48     # 禁止搶占(重要!防止網(wǎng)絡(luò)抖動(dòng)導(dǎo)致頻繁切換)
 49     nopreempt
 50     notify_master "/etc/keepalived/notify_mysql.sh DB_VIP MASTER"
 51     notify_backup "/etc/keepalived/notify_mysql.sh DB_VIP BACKUP"
 52     notify_fault "/etc/keepalived/notify_mysql.sh DB_VIP FAULT"
 53 }
 [root@KA1 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
 
# KA1配置haproxy
 64 listen mysql
 65     bind 0.0.0.0:3306	# MySQL - 綁定所有接口,如果指定172.25.254.200會(huì)起不了服務(wù)
 66     mode tcp
 67     option tcp-check
 68     tcp-check connect port 3306
 69     timeout connect 5s
 70     timeout client 30s
 71     timeout server 30s
 72     server db1 172.25.254.20:3306 check inter 2s rise 2 fall 3
 73     server db2 172.25.254.30:3306 check backup inter 2s rise 2 fall 3
 74
 75 # 統(tǒng)計(jì)頁面
 76 listen stats
 77     bind *:8080
 78     mode http
 79     stats enable
 80     stats uri /stats
 81     stats auth gxf:123
 [root@KA1 ~]# scp /etc/haproxy/haproxy.cfg root@172.25.254.60:/etc/haproxy/haproxy.cfg
haproxy.cfg 
KA2
[root@KA2 ~]# ll /etc/keepalived/notify_mysql.sh /etc/keepalived/check_mysql.sh /etc/keepalived/manual_failover.sh
-rwxr-xr-x 1 root root 1309 Feb 23 06:36 /etc/keepalived/check_mysql.sh
-rwxr-xr-x 1 root root 1175 Feb 23 07:08 /etc/keepalived/manual_failover.sh
-rwxr-xr-x 1 root root 1323 Feb 23 06:50 /etc/keepalived/notify_mysql.sh
[root@KA2 ~]# vim /etc/keepalived/keepalived.conf
  1 ! Configuration File for keepalived
  2
  3 global_defs {
  4    notification_email {
………………
 14    #vrrp_strict
………………
 17    #vrrp_mcast_group4 224.0.0.44
 18    enable_script_security  # 啟用腳本執(zhí)行權(quán)限
 19    script_user root root    # 指定專用用戶,因?yàn)樗胁渴鸲际怯胷oot用戶去部署的
 20 }
 22 vrrp_script check_mysql {
 23     script "/etc/keepalived/check_mysql.sh"
 24     interval 3
 25     weight -30
 26     fall 2
 27     rise 2
 28 }
 30 vrrp_instance DB_VIP {
 31     state MASTER        # KA2作為MASTER
 32     interface eth0
 33     virtual_router_id 52
 34     priority 100        # 高于KA1
 35     advert_int 1
 36     authentication {
 37         auth_type PASS
 38         auth_pass 2222
 39     }
 40     virtual_ipaddress {
 41         172.25.254.200/24 dev eth0 label eth0:0
 42     }
 43     track_script {
 44         check_mysql
 45     }
 47     # 可選:搶占延遲
 48     preempt_delay 10
 50     notify_master "/etc/keepalived/notify_mysql.sh DB_VIP MASTER"
 51     notify_backup "/etc/keepalived/notify_mysql.sh DB_VIP BACKUP"
 52     notify_fault "/etc/keepalived/notify_mysql.sh DB_VIP FAULT"
 53 }
[root@KA2 ~]# keepalived -t -f /etc/keepalived/keepalived.conf
(DB_VIP) Warning - preempt delay will not work with initial state MASTER - clearing
測(cè)試
[root@KA1 ~]# systemctl start keepalived.service
[root@KA2 ~]# systemctl start keepalived.service
[root@KA1 ~]# systemctl start haproxy.service
[root@KA2 ~]# systemctl start haproxy.service
# 查看VIP綁定(應(yīng)該在KA2上)
[root@KA2 ~]# ip addr show eth0 | grep 172.25.254.200
    inet 172.25.254.200/24 scope global secondary eth0:0
tail -f /var/log/keepalived_mysql.log
[root@KA2 ~]# tail -f /var/log/keepalived_mysql.log
2026-02-23 07:49:14 - DB_VIP on KA2 changed to MASTER
Mon Feb 23 07:49:14 AM CST 2026: !!! This node is now MASTER for MySQL VIP !!!
Mon Feb 23 07:49:14 AM CST 2026: VIP 172.25.254.200 is now on KA2
Mon Feb 23 07:49:14 AM CST 2026: ACTION REQUIRED: Please verify and execute manual failover if needed
# 客戶端連接測(cè)試
[root@Client ~]# mysql -h172.25.254.200 -ugxf -p123 -e "SHOW VARIABLES LIKE 'server_id';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 20    |
+---------------+-------+
# 寫入測(cè)試
[root@Client ~]# mysql -h172.25.254.200 -ugxf -p123 -e "INSERT INTO test_haha.t1 VALUES (2, 'Via VIP');"
mysql: [Warning] Using a password on the command line interface can be insecure.
# 檢測(cè)在DB2上驗(yàn)證同步
[root@Client ~]# mysql -h172.25.254.30 -ugxf -p123 -e "SELECT * FROM test_haha.t1;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-----------------+
| id | name            |
+----+-----------------+
|  1 | from Master DB1 |
|  2 | Via VIP         |
+----+-----------------+

# 故障測(cè)試如圖
# 在 DB1 上停止 MySQL
# 觀察 KA 日志
tail -f /var/log/keepalived_mysql_check.log
# 手動(dòng)切換測(cè)試
/etc/keepalived/manual_failover.sh
# 驗(yàn)證新主庫
mysql -h172.25.254.200 -ugxf -p123 -e "SHOW VARIABLES LIKE 'server_id';"

3.3.3 關(guān)鍵配置對(duì)比(數(shù)據(jù)庫與Web)

特性Web(Nginx/HAProxy)數(shù)據(jù)庫(MySQL)
模式雙主(兩個(gè)VIP)單主(一個(gè)VIP)
狀態(tài)MASTER + BACKUP 互換嚴(yán)格區(qū)分 MASTER/BACKUP
搶占默認(rèn)開啟建議 nopreempt
檢測(cè)間隔2秒3秒(更保守)
權(quán)重降幅-20-30(更敏感)
自動(dòng)切換否(建議手動(dòng))
腦裂風(fēng)險(xiǎn)高(必須避免)

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

白城市| 孝义市| 鄂伦春自治旗| 辉南县| 枣强县| 景洪市| 沂南县| 忻州市| 林芝县| 佳木斯市| 洪泽县| 鹤庆县| 柞水县| 库伦旗| 丹东市| 呼玛县| 德庆县| 修武县| 哈密市| 集安市| 怀仁县| 额尔古纳市| 米易县| 高州市| 全州县| 齐齐哈尔市| 南阳市| 绥芬河市| 乾安县| 湟源县| 上林县| 交城县| 嘉峪关市| 射洪县| 高雄市| 德令哈市| 两当县| 周宁县| 诸暨市| 平塘县| 鹤岗市|