keepalived 使用纯 C 语言写成。软件围绕中心的 I/O 多路复用器设计提供实时的网络。它的设计重点是在各个元素之间实现模块化,为了保证稳定性和健壮性,守护进程被分成三个独立的进程。整体设计基于一个简单的父进程,父进程负责 fork 并监控子进程。两个子进程,一个负责 VRRP 框架,另一个负责健康检查。每个子进程有自己的 I/O 调度多路复用器,这样可以优化 VRRP 调度,因为 VRRP 调度比健康检查更敏感。另一方面,这个分开的设计使得健康检查机制对外部函数库的使用最小化,最小化自身的动作并且让主循环空闲来避免自身引起的故障。父进程的监控框架叫做 watchdog,它的设计是:每个子进程打开一个 UNIX 套接字等待请求,当守护进程启动后,父进程连接这些 UNIX 套接字并周期性(5s)地发送 hello 包到子进程。如果父进程无法发送 hello 包到远程连接的 UNIX 套机字,它会简单地重启子进程。watchdog 的设计有两个好处,首先 hello 包从父进程发送到远程连接的子进程是通过 I/O 多路复用器调度,这样它就能够检测子进程调度框架中的死循环。第二个好处是可以使用 sysV 信号检测子进程是否死掉。当启动服务的时候,进程列表:
global_defs { notification_email { [email protected] } notification_email_from [email protected] smtp_server 127.0.0.1 stmp_connect_timeout 30 router_id LVS_DEVEL }
global_defs:全局配置标识
notification_email:表示 keepalived 在发生诸如切换时需要发送 email 通知,以及 email 发送给哪些邮件地址,邮件地址可以是多个,每行一个
notification_email_from:表示发送通知邮件时,邮件的发送者
smtp_server:表示发送邮件时 smtp 服务器地址,这里可以使用本地的 sendmail 来实现
smtp_connect_timeout:连接 smtp 的超时时间
router_id:机器标识
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 地址和路由,在复杂环境下可能需要配置,一般不会用这个来配置
vrrp_sync_group VG_1 { 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 }
group:VRRP 组。http 和 mysql 是实例名,和下面的实例名一致
notify_master:表示当切换到 Master 状态时要执行的脚本
notify_backup:表示当切换到 Backup 状态时要执行的脚本
notify_fault:错误时要执行的脚本
smtp_alert:表示切换时给 global_defs 中定义的邮件地址发送邮件通知
vrrp_instance http { 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 } notify_master /path/to/to_master.sh notify_backup /path_to/to_backup.sh notify_fault "/path/fault.sh VG_1" nopreempt preemtp_delay 300 debug }
state:指定 Instance 的初始状态,但是启动之后还是要通过优先级竞选选定 Master
interface:实例绑定的网卡,因为在配置虚拟 IP 的时候必须是在已有的网卡上添加的
dont_track_primary:忽略 VRRP 的 interface 错误
track_interface:跟踪接口,设置额外的监控,里面任意一块网卡出现问题,都会进入故障(FAULT)状态,例如,用 nginx 做负载均衡的时候,内外网必须工作正常,如果内网出了问题,这个 LB 也无法运作,所以必须对内外网同时做健康检查
mcast_src_ip:发送多播数据包时的源 IP 地址,这里实际上就是在哪个地址上发送 VRRP 通告,这个非常重要,一定要选择稳定的网卡端口来发送,这里相当于 heartbeat 的心跳端口。如果没有设置就使用默认的绑定的网卡的 IP,也就是 interface 指定的地址
garp_master_delay:在切换到 Master 状态后,延迟进行 gratuitous ARP 请求
virtual_router_id:设置 VRID,相同的 VRID 为一组,它将决定多播的 MAC 地址
priority 100:设置本节点的优先级
advert_int:检查间隔,默认为 1 秒
virtual_ipaddress:LVS 的 VIP
virtual_routes:虚拟路由
lvs_sync_daemon_interface:LVS syncd 绑定的网卡
authentication:设置认证
auth_type:认证方式,可以是 PASS 或 AH 两种方式
auth_pass:认证密码
nopreempt:设置不抢占,这里只能设置在 state 为 BACKUP 的节点上,而且这个节点的优先级必须比其他节点高
preempt_delay:抢占延迟
debug:debug 级别
notify_master:和 synchorization group 里设置的含义一样,可以单独设置
vrrp_script check_running { script "/usr/local/bin/check_running" # 执行的脚本 interval 10 # 执行脚本的时间间隔 weight 10 # 检测失败优先级操作 10 表示优先级 +10,-10 表示优先级 -10 fall 2 # 检测尝试次数,也就是认定服务器 down 的检测次数 rise 1 # 认定服务器 up 的次数 } 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 weight 20 } }
首先在 vrrp_script 区域定义脚本名字、脚本执行间隔和脚本执行的优先级变更,然后在实例里面引用。注意:VRRP 脚本和 VRRP 实例属于同一级别
virtual_server_group <STRING> { # VIP port <IPADDR> <PORT> <IPADDR> <PORT> fwmark <INT> }
2.虚拟主机配置
virtual server 可以用下面三种的任意一种来配置:
1. virtual server IP port 2. virtual server fwmark int 3. virtual server group string
virtual_server 172.16.100.1 80 { # 设置一个 virtual server:VIP:PORT delay_loop 6 # 服务轮询的时间间隔 lb_algo rr|wrr|lc|wlc|lblc|sh|sh # LVS 调度算法 lb_kind NAT|DR|TUN # LVS 集群模式 nat_mask 255.255.255.0 persistent_timeout 50 # 会话保持时间(秒) persistent_granularity <NETMASK> # LVS 会话保持粒度,ipvsadm 中的 -M 参数,默认是 0xffffffff,即每个客户端都会话保持 protocol TCP # 协议 sorry_server <IPADDR> <PORT> # 备用机,就是当所有后端 realserver 节点都不可用时,就用这里的设置 real_server <IPADDR> <PORT> { # 后端真实节点主机的权重等设置 weight 1 inhibit_on_failure # 表示在节点失败后,把它权重设置为 0 而不是从 IPVS 中删除 notify_up <STRING>|<QUOTED-STRING> # 检查服务器正常(up)后要执行的脚本 notify_down <STRING>|<QUOTED-STRING> # 检查服务器失败(down)后要执行的脚本 HTTP_GET|SSL_GET { # 健康检查的方式 url { # 要检测的 url,可以有多个 path <STRING> # 测试页面的 URI 路径 digest <STRING> # 摘要码 status_code <INT> # 返回状态码 } connect_port <PORT> # realserver 提供服务的端口 bindto <IPADDR> # realserver 提供服务的地址 connect_timeout <INT> # 连接超时时间 nb_get_retry <INT> # 重试次数 delay_before_retry <INT> # 重试间隔 } TCP_CHECK { connect_port <PORT> bindto <IPADDR> connect_timeout <INT> } SMTP_CHECK { host { connect_ip <IP ADDRESS> connect_port <PORT> bindto <IP ADDRESS> } connect_timeout <INT> retry <INT> delay_before_retry <INT> helo_name <STRING>|<QUOTED-STRING> } MISC_CHECK { misc_path <STRING>|<QUOTED-STRING> # 外部程序或脚本 misc_timeout <INT> # 脚本或程序执行超时时间 misc_dynamic # 通过执行的程序或脚本返回的状态码动态调整 weight 值,使权重根据真实的后端压力来适当调整 } # 返回 0:健康检查没问题,不修改权重 } # 返回 1:健康检查失败,权重设置为 0 } # 返回 2-255:健康检查没问题,但是权重修改为返回代码-2