Keepalived+LB实现高可用架构详细讲解

0 阅读6分钟

引言

在现代IT架构中,高可用性(High Availability)已成为系统设计的核心要求。当负载均衡器(Load Balancer)作为关键流量入口时,其单点故障可能导致整个服务不可用。本篇文章将深入探讨如何使用Keepalived实现虚拟IP(VIP)在负载均衡器之间的自动漂移,构建真正的高可用架构。

keepalived核心概念

什么是Keepalived?

Keepalived是一个基于VRRP(Virtual Router Redundancy Protocol)协议的高可用解决方案,主要用于Linux环境。它通过虚拟IP(VIP)地址的漂移实现服务的高可用性,同时提供负载均衡和健康检查功能。

VRRP协议简介

VRRP协议(虚拟路由协议)允许一组路由器(或服务器)协同工作,形成一个虚拟路由器。这个虚拟路由器拥有自己的虚拟IP地址,客户端只需要与这个虚拟IP通信,而实际的数据转发由Master节点处理。当Master节点故障时,Backup节点会自动接管VIP,实现无缝切换。

VIP作用

  • 统一集群访问控制入口,简化客户端配置
  • 实现自动故障转移,提高系统可用性
  • 支持无缝维护切换,减少服务中断时间
  • 隐藏后端复杂性,客户端无需知道后端有多少台服务器

双LB+keepalived高可用架构

客户端请求
     ↓
 虚拟IP (VIP): 10.0.0.50
     主LB节点: 10.0.0.51 (Master)(正常时)
     备LB节点: 10.0.0.52 (Backup)(故障时)
     ↓
 后端真实服务器集群
     10.0.0.101
     10.0.0.102
     10.0.0.103
     10.0.0.104

keepalived+lb配置及操作

keepalived+lb安装

# CentOS/RHEL
 yum install -y keepalived nginx
 
 # Ubuntu/Debian
 apt-get update
 apt-get install -y keepalived nginx

nginx负载均衡配置

vim /etc/nginx/nginx.conf  #将以下内容添加至http区域
 http {
     upstream backend {
         server 10.0.0.101:80;
         server 10.0.0.102:80;
         server 10.0.0.103:80;
         server 10.0.0.104:80;
     }
     
     server {
         listen 80;
         
         location / {
             proxy_pass http://backend;
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
         }
     }
 }
 
 
 #启动nginx并设置为自启动
 systemctl enable --now nginx

主节点配置(/etc/keepalived/keepalived.conf)

! Configuration File for keepalived
 
 global_defs {
     router_id lb01  # 标识本节点的名称,同一集群中需唯一  
 }
 
 # 定义脚本检查,这里检查Nginx进程
 vrrp_script chk_nginx {
     script "/etc/keepalived/check_nginx.sh"  #执行脚本检查
     interval 2      # 每2秒检查一次
     weight -30      # 健康检查失败时,优先级减少30
     fall 2          # 连续2次失败才认为是真的失败
     rise 1          # 成功1次就认为恢复
 }
 
 vrrp_instance VI_1 {
     state MASTER         # 初始状态,MASTER/BACKUP
     interface eth0       # 绑定VIP的网络接口
     virtual_router_id 51 # 虚拟路由ID,同一集群中必须一致(0-255)
     priority 100         # 初始优先级,MASTER应高于BACKUP
     
     # 主备同步的认证信息
     authentication {
         auth_type PASS
         auth_pass 123456  # 密码,主备必须一致
     }
     # 虚拟IP配置
     virtual_ipaddress {
         10.0.0.50/24 dev eth0 label eth0:0
         #也可直接简单配置
         #10.0.0.50/24
         #可以配置多个VIP
         #10.0.0.60/24 dev eth0 label eth0:1
     }
     
     #健康检查脚本引用
     track_script {
         chk_nginx
     }
     
     # 抢占模式配置
     # preempt          # 开启抢占(默认开启)
     # nopreempt       # 关闭抢占
     preempt_delay 10   # 抢占延迟10秒,避免频繁切换
     
     # 日志配置
     log_file /var/log/keepalived.log
     log_info
 }

备节点配置

! Configuration File for keepalived
 
 global_defs {
     router_id lb02  # 标识本节点的名称,同一集群中需唯一  
 }
 
 vrrp_script chk_nginx {
     script "/etc/keepalived/check_nginx.sh"
     interval 2
     weight -30
     fall 2
     rise 1
 }
 
 vrrp_instance VI_1 {
     state BACKUP      # 初始状态为BACKUP
     interface eth0
     virtual_router_id 51
     priority 90       # 初始优先级低于MASTER
     
     authentication {
         auth_type PASS
         auth_pass 123456
     }
     
     virtual_ipaddress {
         10.0.0.50/24
     }
     
     track_script {
         chk_nginx
     }
     
     preempt_delay 10
     
     log_file /var/log/keepalived.log
     log_info
 }

健康检查脚本 (/etc/keepalived/check_nginx.sh)

#!/bin/bash
 # 简单的健康检查,返回0表示成功,非0表示失败
 
 # 检查Nginx进程
 if ! pgrep -x "nginx" > /dev/null 2>&1; then
     echo "Nginx进程不存在"
     exit 1
 fi
 #!逻辑"非"操作
 #如果pgrep找到进程(返回0),!会使其变为非0(假)
 #如果pgrep没找到进程(返回非0),!会使其变为0(真)
 # > /dev/null 2>&1 让命令静默执行,不产生任何输出
 
 # 检查本地HTTP服务
 HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 http://localhost/ 2>/dev/null || echo "000")
 
 #curl localhost 相当于是curl 本机回环地址127.0.0.1 的80端口,而nginx默认监听 0.0.0.0的80端口,这就意味着curl 本机上的任何ip的80端口都是可以验证nginx进程是否正常。
 #使用localhost或者127.0.0.1可以确保我们检查的是本机,而不受网络配置(如防火墙、路由等)的影响。但是使用宿主机的IP地址(10.0.0.51)进行curl,会经过网络栈,可能会受到本机防火墙规则的影响。如果本机防火墙阻止了来自外部(甚至包括本机)的访问,那么curl 10.0.0.51可能会失败,但nginx实际上可能是正常的。
 #因此,在健康检查脚本中,使用localhost(127.0.0.1)是更安全的选择,因为它不经过网络,直接通过环回接口,可以排除网络配置的问题。
 
 # 判断是否成功状态码
 if [[ "$HTTP_CODE" =~ ^(200|301|302|304)$ ]]; then
     exit 0  # 成功
 else
     echo "HTTP服务异常,状态码: $HTTP_CODE"
     exit 1  # 失败
 fi
 
 
 
 #脚本执行流程
 开始执行
     ↓
 检查Nginx进程是否存在?
     ↓
     ├── 不存在 → 输出错误 → 退出(1)
     ↓
 存在 → 继续
     ↓
 尝试获取HTTP状态码
     ↓
     ├── 成功获取 → 得到具体状态码(200/404/500等)
     ├── 失败获取 → 得到"000"
     ↓
 判断状态码是否在[200, 301, 302, 304]中?
     ↓
     ├── 是 → 退出(0) → Keepalived认为健康
     ↓
 否 → 输出错误信息 → 退出(1) → Keepalived认为不健康
#添加执行权限
 chmod +x /etc/keepalived/check_nginx.sh

测试与验证

1. 启动服务并查看vip绑定状态

# 启动服务
 systemctl start keepalived
 systemctl enable keepalived
 #systemctl enable --now keepalived
 
 # 查看状态
 systemctl status keepalived
 
 # 查看VIP绑定情况
 ip addr show eth0
 # 输出应包含:
 # inet 10.0.0.51brd 10.0.0.255 scope global eth0
 # inet 10.0.0.51/24 scope global secondary eth0:0
 
 #或者使用hostname -I  应有显示vip 10.0.0.50

2. 模拟故障转移测试

# 在主节点上停止keepalived
 systemctl stop keepalived
 
 # 在备节点上检查VIP是否漂移
 ip addr show eth0
 #或者使用hostname -I
 
 # 观察日志
 tail -f /var/log/keepalived.log

3. 网络连通性测试

# 从客户端ping VIP
 ping 10.0.0.50
 
 # 使用curl测试
 curl -I http://10.0.0.50

4. 自动恢复测试

# 重启主节点的keepalived
 systemctl start keepalived
 
 # VIP应该自动回到主节点(如果preempt模式启用)

Keepalived权重调整的VIP漂移机制详解

权重调整的工作原理

权重调整是Keepalived内置的、最优雅的VIP漂移机制。它不是直接停止服务,而是通过动态调整优先级来触发VRRP协议的标准选举过程。

核心概念

1. 优先级(priority)

  • 每个Keepalived节点都有一个优先级(0-255)
  • 优先级高的节点会成为MASTER
  • 默认:MASTER=100,BACKUP=90

2. 权重(weight)

  • 健康检查脚本可以动态调整优先级
  • weight值可以是正数或负数
  • 脚本返回0(成功):优先级 + weight值
  • 脚本返回非0(失败):优先级 - weight值

3. 选举机制

  • 所有节点定期广播自己的优先级
  • 最高优先级的节点自动成为MASTER
  • MASTER节点绑定VIP

权重调整流程详解

初始状态

节点A (10.0.0.51):
   - 状态: MASTER
   - 初始优先级: 100
   - 配置: weight -30
 
 节点B (10.0.0.52):
   - 状态: BACKUP  
   - 初始优先级: 90
   - 配置: weight -30
 
 VIP: 10.0.0.50 绑定在节点A

步骤1:健康检查正常时

节点A:
   - 健康检查脚本: 返回0 (成功)
   - 实际优先级: 100 + 0 = 100  # weight只在失败时生效
   - 状态: MASTER
 
 节点B: 
   - 健康检查脚本: 返回0 (成功)
   - 实际优先级: 90 + 0 = 90
   - 状态: BACKUP
 
 结果: 节点A保持MASTER,持有VIP

步骤2:节点A健康检查失败

节点A:
   - 健康检查脚本: 返回1 (失败)
   - 实际优先级: 100 - 30 = 70  # weight -30生效
   - 状态: MASTER -> 降级
 
 节点B:
   - 健康检查脚本: 返回0 (成功)  
   - 实际优先级: 90 + 0 = 90
   - 状态: BACKUP -> 发现自己的优先级(90) > 节点A的优先级(70)
 
 VRRP协议触发选举:
   1. 节点B发现自己的优先级更高
   2. 节点B广播"我要成为MASTER"
   3. 节点A收到消息,同意节点B成为MASTER
   4. 节点A释放VIP,切换为BACKUP状态
   5. 节点B绑定VIP,切换为MASTER状态
 
 结果: VIP自动漂移到节点B,无需手动停止任何服务

步骤3:节点A恢复健康

节点A:
   - 健康检查脚本: 返回0 (成功)
   - 实际优先级: 100 + 0 = 100  # 恢复原始优先级
   - 状态: BACKUP -> 发现自己的优先级(100) > 节点B的优先级(90)
 
 节点B:
   - 健康检查脚本: 返回0 (成功)
   - 实际优先级: 90 + 0 = 90
   - 状态: MASTER
 
 抢占模式(preempt)决定是否切回:
   1. 如果开启抢占(默认): 节点A重新成为MASTER,VIP切回
   2. 如果关闭抢占(nopreempt): 节点B保持MASTER,除非它故障