keepalived 是一个用 C 语言写的一个路由软件,这个项目的主要目标是能为 Linux 系统和基于 Linux 的基础设施平台提供在负载均衡与高可用上稳定,简单的软件。
keepalived 负载均衡的框架是依赖于著名的并且被广泛使用的 Linux Virtual Server(LVS 的 ipvs)内核模块提供的 Layer 4(OSI 参考模型的第四层,传输层)上的负载均衡。keepalived 实现了一套通过对服务器池(也就是Real Server 池,Server pool)健康状态来动态地、自动维护的管理被负载均衡的服务器池的 checker。
而 keepalived 高可用(High-available)是通过 VRRP 协议来实现的,VRRP 在路由器的故障转移中是非常基础、常用的,而 keepalived 实现了一套 hooks 为 VRRP finite state machine 提供底层,高速的协议互动。
keepalived 框架可以被用于独立的亦或者是全部一起使用来提供弹性服务的基础设施,并且是一个免费,开源的软件。总的来说它能为我们提供这样一些功能:
- 在 LVS 框架上扩展,二者具备良好的兼容性。
- 通过对服务器池的健康检查,对失效机器的故障隔离与通知。
- 通过 VRRP 实现的负载均衡器之间的切换,达到高可用
因为与 LVS 的深入嵌套,避免不了的使用到内核空间,所以整体来说,keepalived 分为两层结构:
- 用户空间
- 内核空间
我们可以通过官网了解到它是这样的一个框架设计:
通过结构图我们了解到 keepalived 涉及到内核空间的两个网络功能,分别是:
- IPVS:LVS 的 IP 负载均衡技术的使用
- NETLINK:提供高级路由及其他相关的网络功能
在用户空间主要分为4个部分,分别是Scheduler I/O Multiplexer、Memory Mangement、Control Plane 和Core components。
- Scheduler I/O Multiplexer:一个I/O复用分发调度器,它负责安排keepalived 所有内部的任务请求。
- Memory Management:一个内存管理机制,这个框架提供的访问内存的一些通用方法。
- Control Plane 是 keepalived 的控制面板,可以实现对配置文件进行编译和解析,keepalived的配置文件解析比较特殊,它只有在用到某模块时才解析相应的配置。
- Core components 是 keepalived 要核心组件,包含了一系列的功能模块,
而其中就会有这样的一些模块:
- WatchDog:监控checkers和VRRP进程的状况;
- Checkers:真实服务器的健康检查 health checking,是 keepalived 最主要的功能;
- VRRP Stack:负载均衡器之间的切换;
- IPVS wrapper:设定规则到内核 ipvs 的接口;
- Netlink Reflector:设定 vrrp 的vip地址等路由相关的功能。
通过上诉我们了解到 keepalived 主要功能实现还是依赖于 LVS 与 VRRP。LVS 我们已经知道是什么了。但是 VRRP 又是什么?
最早的 VRRP 是由 IETF 提出的解决局域网中配置静态网关出现单点失效现象的路由协议,使得在发生故障而进行设备功能切换时可以不影响内外数据通信,不需要再修改内部网络的网络参数。VRRP 协议需要具有IP地址备份,优先路由选择,减少不必要的路由器间通信等功能。
VRRP 协议的功能实现是将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP,而在路由器组内部,通过算法多角度的选举此时的 MASTER 机器作为这个对外 IP 的拥有者,也就是 ARP 的解析,MASTER 的 MAC 地址与 IP 相互对应,其他设备不拥有该 IP,状态是 BACKUP,而 BACKUP 除了接收 MASTER 的 VRRP 状态通告信息外,不执行对外的网络功能。当主机失效时,BACKUP 将立即接管原先 MASTER 的网络功能。从而达到了无缝的切换,而用户并不会知道网络设备出现了故障。
简单来说,vrrp 就是让外界认为只有一个网关在工作(在逻辑结构上将两台虚拟成一台设备),当一般情况下,所有的网络功能都通过 Master 来处理,而其突然出问题的时候,有一个备胎能够立马接替他的工作,而不用用户手动修改自己的电脑配置
而上文所说的 Master,也就是我们的主路由(也就是当前工作的路由)是通过主备路由之间相互通信,通过其 route_id、优先级等来综合判定从而选举出来的,
主路由会每隔 1 秒(这个值可以修改配置)发送 vrrp 包通知 Backup 路由自己还是健康的存活着,而 Backup 路由若是3秒(这个值可以修改)没有收到主路由的 vrrp 包,便会将自己切换成主路由来接替工作。
而若是原主路由突然复活了,在接收到当前主路由发来的 vrrp 包是会从中解析其优先级的值,若是自己的优先级较高便会将自己切换成主路由,并告知当前的主路由,然后开始工作。而当前的路由便会将自己切换成 Backup。
如果优先级相等的话,将比较路由器的实际IP,IP值较大的优先权高;
不过如果对外的虚拟路由器IP就是路由器本身的IP的话,该路由器始终将是MASTER,这时的优先级值为255。
当我们了解了 VRRP 的工作原理之后,我们会发现其实它与 LVS 的工作原理似乎差不多呀,都是虚拟出一个 IP 出来给别人,然后自己在内部通过某种机制来进行切换,这应该便是为什么它们有这么高的契合度的原因.
但是它们还是有区别的:
LVS 在后面的Server Pool 中每台都可以同时工作,而 VRRP 同时工作的机器只有一台,只有当一台出问题之后才会启用另外一台。
所以我们换着方式让两个工具相互结合,让 keepalived 工作在 Load Balancer 上,做好出口路由的高可用,LVS 在后端做好负载均衡,这样大大地提高了我们的服务质量,特别是在突然的大流量冲击下。
LVS + Keepalived 实战
简介
通过上文的学习我们了解到 keepalived 是如何帮我们解决单点故障的问题,但是该如何与 LVS 结合使用呢?我们通过这样的例子来学习。
我们的模拟环境是这样的一个结构:
- 宿主机(本实验桌面环境)模拟客户端;
- 启动一台 docker container 作为我们的 Load Balancer 1 (VIP:192.168.0.10,作为主路由);
- 启动一台 docker container 作为我们的 Load Balancer 2 (VIP:192.168.0.10,作为备份路由);
- 启动一台 docker container 作为我们的 Real Server 1(VIP:192.168.0.10);
- 启动一台 docker container 作为我们的 Real Server 2(VIP:192.168.0.10);
通过这样的步骤来验证我们的实验是否成功:
-
LVS 成功测试一:我们能够通过 VIP 访问我们的 Nginx 站点,经过多次的刷新我们能够访问另一个站点的内容(以显示的内容以作区分,因为负载并不高,所以需要很多次刷新,点击地址栏,按住 F5 不放)
-
LVS 成功测试二:当我们停止当前访问节点的 nginx 服务时,我们还能通过虚拟 IP 访问我们的站点,说明 LVS 在工作,能够将请求分发给另外一台 Real Server
-
keepalived 成功:我们使用
arp -a
查看当前的虚拟 IP 指向的 MAC 地址是 Master 节点的,然后停止 Master 节点的 keepalived 服务,然后还能通过我们的虚拟 IP 访问我们的节点,并且此时通过arp -a
可以看到 虚拟 IP 指向的 Backup 节点的 Mac 地址
我们整体的网络结构如图所示:
宿主机模拟我们的客户端,用浏览器来访问。两个 Load Balancer 作为我们的 VRRP 组。
安装 ipvsadm 工具
首先我们先得在宿主机上安装 ipvsadm 工具,以及使用 ipvsadm 看能否使用(若是没有这一步,在 docker 中将无法使用):
#使用 apt-get 安装 ipvsadm 工具
sudo apt-get install ipvsadm
#使用 ipvsadm 看能否正常工作,并且使用一次,docker 中才能使用,否则会出现 docker 显示读取不到 ipvs 模块的情况
sudo ipvsadm -l
创建docker
同样我们使用 docker 来模拟我们的集群环境,创建四台 container:
- 启动一台 docker container 作为我们的 Load Balancer 1 (VIP:192.168.0.10,作为主路由);
- 启动一台 docker container 作为我们的 Load Balancer 2 (VIP:192.168.0.10,作为备份路由);
- 启动一台 docker container 作为我们的 Real Server 1(VIP:192.168.0.10);
- 启动一台 docker container 作为我们的 Real Server 2(VIP:192.168.0.10);
实际的 IP 地址请查看,以实际的为主,当前通过该顺序创建并以默认的配置参数,IP 地址会这样分配,通过如下的命令来创建:
docker run --privileged --name=LoadBalancer1 -tid ubuntu
docker run --privileged --name=LoadBalancer2 -tid ubuntu
docker run --privileged --name=RealServer1 -tid ubuntu
docker run --privileged --name=RealServer2 -tid ubuntu
相关参数与命令的作用在 LVS 实战中做了详细的解释。
通过 docker ps
我们可以验证我们成功的创建:
配置两台 RealServer 的环境
两台配置的步骤类似,我们提供 RealServer1 的配置步骤
2.3.1 安装 vim 与 nginx 工具
首先我们通过 docker attach
命令登录 RealServer1
# 通过 container 的 name 或者 ID 即可登录
# 登录上之后换行没有反应不是卡住,回车即可看到命令提示符
docker attach RealServer1
然后安装 nginx 来提供 web 服务,vim 来提供编辑器:
apt-get update
apt-get install nginx vim
2.3.2 修改默认的 nginx 展示页面
修改默认的 nginx 展示页面,将其中的 Welcome to Nginx
修改成 Welcome to RealServer1
,在 RealServer2 中的操作则修改成 Welcome to RealServer2
:
vim /usr/share/nginx/html/index.html
完成之后不要忘记启动 nginx:
service nginx start
2.3.3 修改内核参数,抑制 arp
修改 arp 的内核参数配置,来防止 LVS 的集群的 arp 表,从而影响负载均衡机器数据包的接收:
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
回顾以下两个内核参数配置的作用:
arp_ignore
:定义了本机响应 ARP 请求的级别。arp_announce
:定义了发送 ARP 请求时,源 IP 应该填什么。
arp_ignore 部分参数:
0
表示目标 IP 是本机的,则响应 ARP 请求。默认为 0
1
如果接收 ARP 请求的网卡 IP 和目标 IP 相同,则响应 ARP 请求arp_announce 参数:
0
表示使用任一网络接口上配置的本地 IP 地址,通常就是待发送的 IP 数据包的源 IP 地址 。默认为 0
1
尽量避免使用不属于该网络接口(即发送数据包的网络接口)子网的本地地址作为 ARP 请求的源 IP 地址。大致的意思是如果主机包含多个子网,而 IP 数据包的源 IP 地址属于其中一个子网,虽然该 IP 地址不属于本网口的子网,但是也可以作为ARP 请求数据包的发送方 IP。
2
表示忽略 IP 数据包的源 IP 地址,总是选择网络接口所配置的最合适的 IP 地址作为 ARP 请求数据包的源 IP 地址(一般适用于一个网口配置了多个 IP 地址)
2.3.4 创建网卡别名与添加路由
只有在相应 RealServer 中配置了虚拟 IP 地址,该机器才会接收并处理负载均衡机器上发来的数据包(该操作与上一步的修改内核参数都是需要超级权限的,这也就是为什么我们在创建 RealServer 的时候会添加 privileged 参数):
# 添加网卡别名
ifconfig lo:0 192.168.0.10 broadcast 192.168.0.10 netmask 255.255.255.255 up
# 添加路由
route add -host 192.168.0.10 dev lo:0
由此我们便完成了其中一台 RealServer 的环境配置,我们只需要在另外一台做相同的操作即可,完成两台 RealServer 的配置之后我们通过 Firefox 浏览器来验证我们的 Web 服务是否正常工作。
完成 RealServer 的配置之后,紧接着便是 LoadBalancer 机器的配置。
配置两台 LoadBalancer 环境
2.4.1 安装 ipvsadm 与 Keepalived
同样我们首先登录 LoadBalancer1 中更新源与安装相关的工具:
# 因为镜像中默认是 ubuntu 原生源,所以有时候比较慢
apt-get update
# 安装 ipvsadm 与 keepalived
apt-get install ipvsadm keepalived vim
# 验证 ipvsadm
ipvsadm -l
紧接着在 LoadBalancer2 中做相同的操作 .
2.4.2 修改 Keepalived 的配置文件
因为 Keepalived 就是为 LVS 而诞生的,它会调用 IPVS 模块,所以此时我们并不需要再去通过 ipvsadm 工具来编写规则,我们直接将我们要做的配置写在配置文件中,Keepalived 会根据配置文件自动的为我们配置。
首先我们修改 LoadBalancer1 中的 Keepalived 配置文件:
vim /etc/keepalived/keepalived.conf
因为我们将 LoadBalancer1 作为我们的主路由器,所以其配置文件为:
#全局配置,在发现某个节点出故障的时候以邮件的形式通知管理员
global_defs {
notification_email { #设置报警邮件地址,可以设置多个
shiyanlouAdmin@localhost #每行一个,如果开启邮件报警,需要开启本机的 Sendmail 服务
shiyanlou@admin.com
}
notification_email_from root #设置邮件的发送地址
smtp_server 127.0.0.1 #设置 STMP 服务器地址
smtp_connect_timeout 30 #设置连接 SMTP 服务器的超时时间
router_id LVS_DEVEL #标识,发邮件时显示在邮件主题中的信息
}
#配置 vrrp 实例
vrrp_instance VI_1 {
state MASTER #指定 Keepalived 角色, MASTER 表示此主机是主服务器,BACKUP 表示此主机是备用服务器
interface eth0 #指定 HA 检测网络的接口
virtual_router_id 51 #虚拟路由标识,这个标识是一个数字,同一个 vrrp_instance 下,MASTER 和BACKUP 必须是一致的
priority 101 #定义优先级,数字越大,优先级越高。在同一个 vrrp_instance 下,MASTER 的优先级必须大于 BACKUP 的优先级
advert_int 1 #设定 MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位是秒
authentication { #配置 vrrp 直接的认证
auth_type PASS #设定验证类型和密码,验证类型分为 PASS 和 AH 两种
auth_pass 1111 #设置验证密码,在一个 vrrp_instance 下,MASTER 与 BACKUP 必须使用相同的密码才能通信
}
virtual_ipaddress { #配置虚拟 IP,可以设置多个,每行一个
192.168.0.10
}
}
#配置虚拟服务器
virtual_server 192.168.0.10 80 { #配置虚拟服务器,需要指定虚拟 IP 地址和端口,IP 与端口用空格隔开
delay_loop 6 #设置运行情况检查时间,单位是秒
lb_algo rr #设置负载调度算法,这里设置为 rr,即论叫算法
lb_kind DR #设置 LVS 实现负载均衡的机制,有 NAT,TUN,DR 三个模式可选,这里选择 DR
#persistence_timeout 50 会话保持时间,单位是秒,一般针对动态网页很有用,这里需要这个配置
protocol TCP #指定协议转发类型,有 TCP 和 UDP 两种。
real_server 192.168.0.4 80 { #配置 real server 的信息,服务节点1
weight 1 #配置该节点的权重,权值大小用数字表示,设置权值的大小可以分不同性能的服务器分配不同的负载,性能较低的方服务器,设置权值较低,这样能合理地利用和分配系统资源
HTTP_GET { #设置健康检查
url { #访问这个地址,判断状态码是否 200
path /
status_code 200
}
connect_timeout 3 #表示3秒无响应超时
nb_get_retry 3 #表示重试次数
delay_before_retry 3 #表示重试间隔
}
}
real_server 192.168.0.5 80 { #配置服务节点2
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
以上配置内容为 LoadBalancer1 的 Keepalived.conf 配置内容。在编写配置内容时。一定要注意文字和语法格式,因为 Keepalived 在启动时并不会检测配置文件的正确性,及时没有配置文件,Keepalived 也能正常启动,所以一定要保证配置文件内容的正确性。
紧接着我们在 LoadBalancer2 中做相同的配置,主需要将 "Master" 修改成 "BACKUP",以及优先级的调整即可。