Keepalived 原理介绍和配置实践

负载均衡(LB)

负载均衡实现方法有两种:硬件实现和软件实现

硬件比较常见的有:

  1. F5 Big-IP
  2. Citrix Netscaler

软件比较常见的有:

  • LVS(Linux Virtual Server)
  • HAProxy
  • Nginx

LVS 特点是:

  • 首先它是基于 4 层的网络协议的,抗负载能力强,对于服务器的硬件要求除了网卡外,其他没有太多要求;
  • 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,大大减少了人为出错的几率;
  • 应用范围比较广,不仅仅对 web 服务做负载均衡,还可以对其他应用(mysql)做负载均衡;
  • LVS 架构中存在一个虚拟 IP 的概念,需要向 IDC 多申请一个 IP 来做虚拟 IP。

Nginx 负载均衡器的特点是:

  • 工作在网络的 7 层之上,可以针对 http 应用做一些分流的策略,比如针对域名、目录结构;

  • Nginx 安装和配置比较简单,测试起来比较方便;

  • 也可以承担高的负载压力且稳定,一般能支撑超过上万次的并发;

  • Nginx 可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点,不过其中缺点就是不支持url 来检测;

  • Nginx 对请求的异步处理可以帮助节点服务器减轻负载;

  • Nginx 能支持 http 和 Email,这样就在适用范围上面小很多;

  • 默认有三种调度算法: 轮询、weight 以及 ip_hash(可以解决会话保持的问题),还可以支持第三方的 fair 和 url_hash 等调度算法;

HAProxy 的特点是:

  • HAProxy 是工作在网络 7 层之上;

  • 支持 Session 的保持,Cookie 的引导等;

  • 支持 url 检测后端的服务器出问题的检测会有很好的帮助;

  • 支持的负载均衡算法:动态加权轮循(Dynamic Round Robin),加权源地址哈希(Weighted Source Hash),加权 URL 哈希和加权参数哈希(Weighted Parameter Hash);

  • 单纯从效率上来讲 HAProxy 更会比 Nginx 有更出色的负载均衡速度;

  • HAProxy 可以对 Mysql 进行负载均衡,对后端的 DB 节点进行检测和负载均衡。

keepalived 简介

Keepalived 是运行在 lvs 之上,是一个用于做双机热备(HA)的软件,它的主要功能是实现真实机的故障隔离及负载均衡器间的失败切换,提高系统的可用性。

运行原理
keepalived 通过选举(看服务器设置的权重)挑选出一台热备服务器做 MASTER 机器,MASTER 机器会被分配到一个指定的虚拟 ip,外部程序可通过该 ip 访问这台服务器,如果这台服务器出现故障(断网,重启,或者本机器上的 keepalived crash 等),keepalived 会从其他的备份机器上重选(还是看服务器设置的权重)一台机器做 MASTER 并分配同样的虚拟 IP,充当前一台 MASTER 的角色。

选举策略
选举策略是根据 VRRP 协议,完全按照权重大小,权重最大(0~255)的是 MASTER 机器,下面几种情况会触发选举

  • keepalived 启动的时候
  • master 服务器出现故障(断网,重启,或者本机器上的 keepalived crash 等,而本机器上其他应用程序 crash 不算)
  • 有新的备份服务器加入且权重最大

keepalived 的配置文件说明

Keepalived 是运行在 lvs 之上, 它的主要功能是实现 RealServer(真实服务器)的故障隔离及 Director(负载均衡器)间的 FailOver(失败切换).

  • keepalived 是 lvs 的扩展项目, 因此它们之间具备良好的兼容性
  • 对 RealServer 的健康检查, 实现对失效机器 / 服务的故障隔离
  • 负载均衡器之间的失败切换 failover
全局定义

全局配置又包括两个子配置

  1. 全局定义(global definition)
  2. 静态路由配置(static ipaddress/routes)
# 全局定义 (global definition) 
global_defs {                      
   notification_email {      
   acassen@firewall.loc     
   failover@firewall.loc
   sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc   
   smtp_server 192.168.200.1                         
   smtp_connect_timeout 30                                  
   router_id LVS_DEVEL     
}
notification_email: 表示 keepalived 在发生诸如切换操作时需要发送 email 通知以及 email 发送给哪些邮件地址邮件地址可以多个每行一个
notification_email_from admin@example.com: 表示发送通知邮件时邮件源地址是谁
smtp_server 127.0.0.1: 表示发送 email 时使用的 smtp 服务器地址这里可以用本地的 sendmail 来实现
smtp_connect_timeout 30: 连接 smtp 连接超时时间
router_id node1: 机器标识,通常配置主机名

# 静态地址和路由配置范例
static_ipaddress {
    192.168.1.1/24 brd + dev eth0 scope global
    192.168.1.2/24 brd + dev eth1 scope global
}
static_routes {
    src $SRC_IP to $DST_IP dev $SRC_DEVICE
    src $SRC_IP to $DST_IP via $GW dev $SRC_DEVICE
}
 这里实际上和系统里面命令配置 IP 地址和路由一样例如 
192.168.1.1/24 brd + dev eth0 scope global 相当于: ip addr add 192.168.1.1/24 brd + dev eth0 scope global
 就是给 eth0 配置 IP 地址路由同理, 一般这个区域不需要配置 
 这里实际上就是给服务器配置真实的 IP 地址和路由的在复杂的环境下可能需要配置一般不会用这个来配置我们可以直接用 vi /etc/sysconfig/network-script/ifcfg-eth1 来配置切记这里可不是 VIP 不要搞混淆了切记切记

VRRPD 配置

包括三个类:

  1. VRRP 同步组(synchroization group)
  2. VRRP 实例(VRRP Instance)
  3. VRRP 脚本

# VRRP 同步组 (synchroization group) 配置范例 
vrrp_sync_group VG_1 {   // 注意 vrrp_sync_group  后面可自定义名称如 lvs_httpd ,httpd
group {
http
mysql
}
notify_master /path/to/to_master.sh
notify_backup /path_to/to_backup.sh
notify_fault "/path/fault.sh VG_1"
notify /path/to/notify.sh
smtp_alert 
}
 其中 http 和 mysql 是实例名和下面的实例名一致 
notify_master /path/to/to_master.sh // 表示当切换到 master 状态时要执行的脚本
notify_backup /path_to/to_backup.sh // 表示当切换到 backup 状态时要执行的脚本
notify_fault "/path/fault.sh VG_1"  // keepalived 出现故障时执行的脚本
notify /path/to/notify.sh  
smtp_alert           // 表示切换时给 global defs 中定义的邮件地址发送邮件通知

# VRRP 实例(instance) 配置范例
vrrp_instance http {  // 注意 vrrp_instance 后面可自定义名称如 lvs_httpd ,httpd
state MASTER
interface eth0
dont_track_primary
track_interface {
eth0
eth1
}
mcast_src_ip <IPADDR>
garp_master_delay 10
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
autp_pass 1234
}
virtual_ipaddress {
#<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPT> label <LABEL>
192.168.200.17/24 dev eth1
192.168.200.18/24 dev eth2 label eth2:1
}
virtual_routes {
# src <IPADDR> [to] <IPADDR>/<MASK> via|gw <IPADDR> dev <STRING> scope <SCOPE> tab
src 192.168.100.1 to 192.168.109.0/24 via 192.168.200.254 dev eth1
192.168.110.0/24 via 192.168.200.254 dev eth1
192.168.111.0/24 dev eth2
192.168.112.0/24 via 192.168.100.254
}
nopreempt
preemtp_delay 300
debug
}

state: state 指定 instance(Initial)的初始状态就是说在配置好后这台 服务器的初始状态就是这里指定的但这里指定的不算还是得要通过竞选通过优先级来确定里如果这里设置为 master 但如若他的优先级不及另外一台 那么这台在发送通告时会发送自己的优先级另外一台发现优先级不如自己的高那么他会就回抢占为 master

interface: 实例绑定的网卡因为在配置虚拟 VIP 的时候必须是在已有的网卡上添加的

dont track primary: 忽略 VRRP 的 interface 错误

track interface: 跟踪接口设置额外的监控里面任意一块网卡出现问题都会进入故障 (FAULT) 状态例如用 nginx 做均衡器的时候内网必须正常工作如果内网出问题了这个均衡器也就无法运作了所以必须对内外网同时做健康检查

mcast src ip: 发送多播数据包时的源 IP 地址这里注意了这里实际上就是在那个地址上发送 VRRP 通告这个非常重要一定要选择稳定的网卡端口来发送这里相当于 heartbeat 的心跳端口如果没有设置那么就用默认的绑定的网卡的 IP 也就是 interface 指定的 IP 地址

garp master delay: 在切换到 master 状态后延迟进行免费的 ARP(gratuitous ARP)请求,默认 5s

virtual router id: 这里设置 VRID 这里非常重要相同的 VRID 为一个组他将决定多播的 MAC 地址

priority 100: 设置本节点的优先级优先级高的为 master

advert int: 设置 MASTER 与 BACKUP 负载均衡之间同步即主备间通告时间检查的时间间隔, 单位为秒,默认 1s

virtual ipaddress: 这里设置的就是 VIP 也就是虚拟 IP 地址他随着 state 的变化而增加删除当 state 为 master 的时候就添加当 state 为 backup 的时候删除这里主要是有优先级来决定的和 state 设置的值没有多大关系这里可以设置多个 IP 地址

virtual routes: 原理和 virtual ipaddress 一样只不过这里是增加和删除路由

lvs sync daemon interface: lvs syncd 绑定的网卡,类似 HA 中的心跳检测绑定的网卡

authentication: 这里设置认证

auth type: 认证方式可以是 PASS 或 AH 两种认证方式

auth pass: 认证密码

nopreempt: 设置不抢占 master,这里只能设置在 state 为 backup 的节点上而且这个节点的优先级必须别另外的高,比如 master 因为异常将调度圈交给了备份 serve,master serve 检修后没问题,如果不设置 nopreempt 就会将调度权重新夺回来,这样就容易造成业务中断问题

preempt delay: 抢占延迟多少秒,即延迟多少秒后竞选 master

debug:debug 级别

notify master:和 sync group 这里设置的含义一样可以单独设置例如不同的实例通知不同的管理人员 http 实例发给网站管理员 mysql 的就发邮件给 DBA


# VRRP 脚本 
# 如下所示为相关配置示例
vrrp_script check_running {
   script "/usr/local/bin/check_running"
   interval 10
   weight 10
}

vrrp_instance http {
   state BACKUP
   smtp_alert
   interface eth0
   virtual_router_id 101
   priority 90
   advert_int 3
   authentication {
   auth_type PASS
   auth_pass whatever
   }
   virtual_ipaddress {
   1.1.1.1
   }
   track_script {
   check_running 
   }
}
# 首先在 vrrp_script 区域定义脚本名字和脚本执行的间隔和脚本执行的优先级变更, 如下所示:
vrrp_script check_running {
            script "/usr/local/bin/check_running"
            interval 10     # 脚本执行间隔
            weight 10       # 脚本结果导致的优先级变更 10 表示优先级 + 10-10 则表示优先级 - 10
            }
# 然后在实例(vrrp_instance) 里面引用有点类似脚本里面的函数引用一样先定义后引用函数名
track_script {
      check_running 
}

注意:
VRRP 脚本 (vrrp_script) 和 VRRP 实例 (vrrp_instance) 属于同一个级别
keepalived 会定时执行脚本并对脚本执行的结果进行分析,动态调整 vrrp_instance 的优先级。一般脚本检测返回的值为 0,说明脚本检测成功,如果为非 0 数值,则说明检测失败
如果脚本执行结果为 0,并且 weight 配置的值大于 0,则优先级相应的增加, 如果 weight 为非 0,则优先级不变
如果脚本执行结果非 0,并且 weight 配置的值小于 0,则优先级相应的减少, 如果 weight 为 0,则优先级不变
其他情况,维持原本配置的优先级,即配置文件中 priority 对应的值。
这里需要注意的是:
1) 优先级不会不断的提高或者降低
2) 可以编写多个检测脚本并为每个检测脚本设置不同的 weight
3) 不管提高优先级还是降低优先级,最终优先级的范围是在[1,254],不会出现优先级小于等于 0 或者优先级大于等于 255 的情况
这样可以做到利用脚本检测业务进程的状态,并动态调整优先级从而实现主备切换。

virtual_server 虚拟主机配置

关于 keeplived 的虚拟主机配置有三种如下所示
virtual server IP port
virtual server fwmark int
virtual server group string

以常用的第一种为例
virtual_server 192.168.1.2 80
含义: 设置一个 virtual server: VIP:Vport

delay_loop 3
含义: 设置 service polling 的 delay 时间即服务轮询的时间间隔

lb_algo rr|wrr|lc|wlc|lblc|sh|dh
含义: 设置 LVS 调度算法

lb_kind NAT|DR|TUN
含义: 设置 LVS 集群模式

persistence_timeout 120
含义: 设置会话保持时间秒为单位即以用户在 120 秒内被分配到同一个后端 realserver, 超过此时间就重新分配

persistence_granularity
含义: 设置 LVS 会话保持粒度 ipvsadm 中的 - M 参数默认是 0xffffffff 即每个客户端都做会话保持

protocol TCP
含义: 设置健康检查用的是 TCP 还是 UDP

ha_suspend
含义: suspendhealthchecker’s activity

virtualhost
含义: HTTP_GET 做健康检查时检查的 web 服务器的虚拟主机即 host 头

sorry_server
含义: 设置 backupserver 就是当所有后端 realserver 节点都不可用时就用这里设置的也就是临时把所有的请求都发送到这里

real_server
含义: 设置后端真实节点主机的权重等设置主要后端有几台这里就要设置几个

weight 1
含义: 设置给每台的权重 0 表示失效 (不知给他转发请求知道他恢复正常) 默认是 1

inhibit_on_failure
含义: 表示在节点失败后把他权重设置成 0 而不是冲 IPVS 中删除

notify_up |
含义: 设置检查服务器正常 (UP) 后要执行的脚本
notify_down |
含义: 设置检查服务器失败 (down) 后要执行的脚本

注: keepalived 检查机制说明
keepalived 健康检查方式有: HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK 几种如下所示

#HTTP/HTTPS 方式 
HTTP_GET|SSL_GET {      # 设置健康检查方式

url {                   # 设置要检查的 URL 可以有多个
path /                  # 设置 URL 具体路径
digest <STRING>         # 检查后的摘要信息这些摘要信息可以通过 genhash 命令工具获取                                   
status_code 200         # 设置返回状态码
}
connect_port 80         # 设置监控检查的端口
bindto  <IPADD>         # 设置健康检查的 IP 地址
connect_timeout   3     # 设置连接超时时间
nb_get_retry  3         # 设置重连次数
delay_before_retry  2   # 设置重连间隔
} 

#TCP 方式  
TCP_CHECK     {
connect_port 80         # 设置监控检查的端口
bindto  <IPADD>         # 设置健康检查的 IP 地址
connect_timeout   3     # 设置连接超时时间
nb_get_retry  3         # 设置重连次数
delay_before_retry  2   # 设置重连间隔
}
#SMTP 方式 (这个可以用来给邮件服务器做集群)
SMTP_CHECK {
host {
connect_ip <IP ADDRESS>
connect_port <PORT>     # 默认检查 25 端口
14 KEEPALIVED
bindto <IP ADDRESS>
}
connect_timeout <INTEGER>
retry <INTEGER>
delay_before_retry <INTEGER>
helo_name <STRING>|<QUOTED-STRING>
} 

#MISC 方式 这个可以用来检查很多服务器只需要自己会些脚本即可
MISC_CHECK {
misc_path <STRING>|<QUOTED-STRING>  # 外部程序或脚本
misc_timeout <INT>                  # 脚本或程序执行超时时间
misc_dynamic                                              
# 这个就很好用了可以非常精确的来调整权重是后端每天服务器的压力都能均衡调配这个主要是通过执行的程序或脚本返回的状态代码来动态调整 weight 值使权重根据真实的后端压力来适当调整不过这需要有过硬的脚本功夫才行哦
# 返回 0 健康检查没问题不修改权重
# 返回 1 健康检查失败权重设置为 0
# 返回 2-255 健康检查没问题但是权重却要根据返回代码修改为返回码 - 2 例如如果程序或脚本执行后返回的代码为 200# 那么权重这回被修改为 200-2
}

以上就是 keepalived 的配置项说明虽然配置项很多但很多时候很多配置项保持默认即可,以下是默认配置文件,方便大家做个对比参考

[root@sg-gop-10-65-32-140 wangao]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.16
        192.168.200.17
        192.168.200.18
    }
}

virtual_server 192.168.200.100 443 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.201.100 443 {
        weight 1
        SSL_GET {
            url {
              path /
              digest ff20ad2481f97b1754ef3e12ecd3a9cc
            }
            url {
              path /mrtg/
              digest 9b3a0c85a887a256d6939da88aabd8cd
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

virtual_server 10.10.10.2 1358 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    sorry_server 192.168.200.200 1358

    real_server 192.168.200.2 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.200.3 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

virtual_server 10.10.10.3 1358 {
    delay_loop 3
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.200.4 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.200.5 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}
最简单的 Keepalived HA 配置实例
# 安装 keepalived,ipvsadm
yum install keepalived -y

# 如果开启防火墙,请添加 VRRP 白名单
-A INPUT -p vrrp -j ACCEPT
-A INPUT -p igmp -j ACCEPT
-A INPUT -d 224.0.0.18 -j ACCEPT

# 编辑 keepalived 配置文件,master 和 backup 节点配置文件一样
vi /etc/keepalived/keepalived.conf

vrrp_sync_group VI_GOP_NC1_HA {
    group {
        VI_GOP_NC1_HA_PRI
    }
}

vrrp_instance VI_GOP_NC1_HA_PRI {
    state BACKUP
    interface bond0
    virtual_router_id 139
    priority 100
    advert_int 1
    nopreempt
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.65.33.139/23 dev bond0
    }
}

# 手动启动节点即为 master
service keepalived start
简单的 Keepalived 邮件告警实例

编写 sendmail.py 邮件发送脚本
在 keepalived.conf 中配置 notify_backup

import sys
import socket
import smtplib

EMAIL_CONFIG = {
    'EMAIL_HOST': 'xxx',
    'EMAIL_HOST_USER': 'xxx',
    'EMAIL_RECEIVER': 'xxx'
}

def _get_private_ip():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        sock.connect(('10.255.255.255', 1))
        return sock.getsockname()[0]
    except:
        return '127.0.0.1'
    finally:
        sock.close()

def send_email():
    ip = _get_private_ip()
    hostname = socket.gethostname()
    message = 'Subject: Keepalived Failover Alert %s \n\nHOSTNAME %s on LANIP %s HA status has changed to %s' % (
        sys.argv[1], hostname, ip, sys.argv[1])
    server = smtplib.SMTP(EMAIL_CONFIG["EMAIL_HOST"])
    server.sendmail(EMAIL_CONFIG['EMAIL_HOST_USER'],
                    EMAIL_CONFIG['EMAIL_RECEIVER'], message)
    server.quit()

send_email()

如果有设置 vrrp_sync_group 可以添加在这里通过群组控制,如果没有就跟在 vrrp_instance 独立设置

 # notify scripts and alerts are optional
           #
           # filenames of scripts to run on transitions can be unquoted (if
           # just filename) or quoted (if it has parameters)
           # The username and groupname specify the user and group
           # under which the scripts should be run. If username is
           # specified, the group defaults to the group of the user.
           # If username is not specified, they default to the
           # global script_user and script_group to MASTER transition
           notify_master /path/to_master.sh [username [groupname]]

           # to BACKUP transition
           notify_backup /path/to_backup.sh [username [groupname]]

           # FAULT transition
           notify_fault "/path/fault.sh VG_1" [username [groupname]]

vrrp_sync_group NC-CLOUD-LOADTEST {
    group {
        NC-CLOUD-LOADTEST-PUB
        NC-CLOUD-LOADTEST-PRI
    }
    notify_master "/bin/python /etc/keepalived/sendmail.py master"
    notify_backup "/bin/python /etc/keepalived/sendmail.py backup"
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值