使用Keepalived构建LVS高可用集群
LVS的DR模型配置+Keepalive部署
介绍
下图为DR模型的通信过程,图中的IP不要被扑结构中的IP迷惑,图里只是为了说明DR的通信原理,应用到本例中的拓扑上其工作原理不变。
拓扑结构
服务器 | IP地址 | 角色 |
---|---|---|
Srv01 | 172.16.42.100 VIP: 172.16.42.111 |
LVS+Keepalive |
Srv02 | 172.16.42.101 VIP: 192.168.100.1 |
LVS+Keepalive |
Srv03 | 172.16.42.102 VIP: 172.16.42.111 |
Nginx |
Srv04 | 172.16.42.103 VIP: 172.16.42.111 |
Nginx |
另外,我这4台主机都是2个网卡, 其中有ens33是172.16.42.0/24这个网络,ens34是192.168.100.0/24网络,这个网络在本例中没有用,请忽略。
设置后端服务器
ARP的内核参数
由于LVS服务器和后端服务器的网卡上都配置了VIP,那么当客户端联系VIP的时候肯定是和LVS服务器的VIP进行通信,然后由LVS服务器基于规则进行调度,我们知道2层通信是基于MAC地址的,那么首次通信时客户端可能并不知道LVS服务器的MAC地址,那么就需要进行ARP广播来解析出VIP所在的服务器的MAC地址,那么显然对客户端进行ARP应答的只能是LVS服务器不能是后端服务器,所以我们就要在后端上修改内核参数来禁止ARP应答和宣告。那么有2个内核参数表示这两个设置:
arp_ignore:表示接收到ARP广播时的响应级别,默认值为0
0,默认值,表示响应所有,只要对方查询的IP配置在我自己这台主机上且无论ARP请求从哪个网卡进来,该主机都会响应
1,收到该ARP请求的网卡IP与ARP请求的IP一致,该主机才响应
arp_announce:定义将自己的地址向外通告的级别,默认是0
0,表示将本机所有的MAC地址都向外通告
1,多网卡主机且都配置了IP地址,那么该主机接入到网络时,无论哪个网卡接入到网络,该网卡都会向外宣告自己所有的MAC地址,所以1表示如果IP不在这个接口上,就避免向外通告,但是不保证一定不会下外通告。
2,仅向网卡IP直连的网络进行通告
为什么会有这些级别呢?因为主机可以有多个网卡,每个网卡都对应一个网段,默认情况下这个多网卡主机只要接入网络它就会把自己所在的所有网络地址都向外进行通告。
所以对于后端服务器,也就是本例子中的Nginx,我们应该在lo上配置子接口,且设置arp_ignore为1,arp_announce为2。
设置后端服务器
后端服务器的所有操作都是一样,我这里就演示一台。首先要保证2台后端服务器都安装了Nginx,我用Nginx只是为了后端提供一个Web服务而已,你使用Tomcat也是一样的。
通过这个命令查看当前服务器设置sysctl -a | egrep "arp_ignore|arp_announce"
可以看到这里每个网卡都有这2个参数还有一个All也有,那应该配置在哪里呢?all表示全局,理论上来说在all上配置就可以,但是为了保险我们在ens33上也配置。
记住arp_announce配置为2;apr_ignore配置为1。
sysctl -w net.ipv4.conf.all.arp_announce=2
sysctl -w net.ipv4.conf.ens33.arp_announce=2
我使用sysctl -w来修改只是临时生效,重启就没有了,为了永久有效请修改
/etc/sysctl.conf
文件。
现在在说以为什么arp_announce配置为2,我这个主机有2个网卡,每个网卡所连接的是不同网段。我要使用的是ens33上面这个172.16.42.0/24这个网段,且VIP也是这个网段,当我把ens33的apr_announce配置为2 的时候,这就意味着当这个ens33接入网络时它不会对外宣告ens34的网络设置,也不会对外宣告lo的网络设置(因为我们要在lo上配置一个子接口,该接口的IP就是VIP),下面配置apr_ignore
sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.ens33.arp_ignore=1
下面设置lo的子接口,这里为什么要32位呢?因为要把广播地址设置为自己,这样它的广播就不会广播到其他地方。
ifconfig lo:0 172.16.42.111 netmask 255.255.255.255 broadcast 172.16.42.111 up
下面我们在Srv01上ping一下这个地址,发现没有人应答,所以ping不通。
接下来添加一条路由,其目的是由于后端服务器是直接应答客户端请求的,所以就需要确保应答是其源IP一定是VIP(因为客户端请求的就是VIP),但是当LVS修改完数据包发送给后端服务器时,使用的是后端服务器的真实IP地址进行通信的,而网络通信是请求入栈是哪个接口,响应出栈还走哪个接口,这就势必导致后端服务器会使用自己的真实IP而不是VIP对客户端响应,这肯定是不对的,所以我们要通过这一条路由设置让ens33网卡收到数据包后转发给lo:0这个子接口,这样响应出栈的时候就会经过lo:0,这样也就会把响应报文的源IP设置为VIP了。
route add -host 172.16.42.111 dev lo:0
这条命令的含义是如果目标地址是172.16.42.111就要送到lo:0,这样就保证了入栈经过lo:0,那么出栈自然会经过。如果你不理解,那么就要好好看看最上面的图,二层通信是使用mac地址,而此时后端服务器收到这个数据包的时候,IP报文中源IP是客户端的IP,而目标IP则是VIP,只是数据链路层报文mac地址信息被LVS替换了。
之后启动后端服务的Nginx服务,两台后端服务器上都做上面的修改。
安装keepalive
之间通过yum安装即可yum install -y keepalived
。我这里使用的是阿里云的源,它默认就在里面,如下图:
在2个节点都安装。
文件 | 说明 |
---|---|
/usr/sbin/keepalived | 二进制程序 |
/etc/keepalived/keepalived.conf | 配置文件 |
/usr/lib/systemd/system/keepalived.service | 服务文件 |
Keepalive配置文件说明
# 全局配置
global_defs {
# 邮件通知信息
notification_email {
# 定义收件人
acassen@firewall.loc
}
# 定义发件人
notification_email_from Alexandre.Cassen@firewall.loc
# SMTP服务器地址
smtp_server 192.168.200.1
smtp_connect_timeout 30
# 路由器标识,一般不用改,也可以写成每个主机自己的主机名
router_id LVS_DEVEL
# VRRP的ipv4和ipv6的广播地址,配置了VIP的网卡向这个地址广播来宣告自己的配置信息,下面是默认值
vrrp_mcast_group4 224.0.0.18
vrrp_mcast_group6 ff02::12
}
# 定义用于实例执行的脚本内容,比如可以在线降低优先级,用于强制切换
vrrp_script SCRIPT_NAME {
}
# 一个vrrp_instance就是定义一个虚拟路由器的,实例名称
vrrp_instance VI_1 {
# 定义初始状态,可以是MASTER或者BACKUP
state MASTER
# 工作接口,通告选举使用哪个接口进行
interface ens33
# 虚拟路由ID,如果是一组虚拟路由就定义一个ID,如果是多组就要定义多个,而且这个虚拟
# ID还是虚拟MAC最后一段地址的信息,取值范围0-255
virtual_router_id 51
# 使用哪个虚拟MAC地址
use_vmac XX:XX:XX:XX:XX
# 监控本机上的哪个网卡,网卡一旦故障则需要把VIP转移出去
track_interface {
eth0
ens33
}
# 如果你上面定义了MASTER,这里的优先级就需要定义的比其他的高
priority 100
# 通告频率,单位为秒
advert_int 1
# 通信认证机制,这里是明文认证还有一种是加密认证
authentication {
auth_type PASS
auth_pass 1111
}
# 设置虚拟VIP地址,一般就设置一个,在LVS中这个就是为LVS主机设置VIP的,这样你就不用自己手动设置了
virtual_ipaddress {
# IP/掩码 dev 配置在哪个网卡
192.168.200.16/24 dev eth1
# IP/掩码 dev 配置在哪个网卡的哪个别名上
192.168.200.17/24 dev label eth1:1
}
# 虚拟路由,在需要的情况下可以设置lvs主机 数据包在哪个网卡进来从哪个网卡出去
virtual_routes {
192.168.110.0/24 dev eth2
}
# 工作模式,nopreempt表示工作在非抢占模式,默认是抢占模式 preempt
nopreempt|preempt
# 如果是抢占默认则可以设置等多久再抢占,默认5分钟
preempt delay 300
# 追踪脚本,通常用于去执行上面的vrrp_script定义的脚本内容
track_script {
}
# 三个指令,如果主机状态变成Master|Backup|Fault之后会去执行的通知脚本,脚本要自己写
notify_master ""
notify_backup ""
notify_fault ""
}
# 定义LVS集群服务,可以是IP+PORT;也可以是fwmark 数字,也就是防火墙规则
# 所以通过这里就可以看出来keepalive天生就是为ipvs而设计的
virtual_server 10.10.10.2 1358 {
delay_loop 6
# 算法
lb_algo rr|wrr|lc|wlc|lblc|sh|dh
# LVS的模式
lb_kind NAT|DR|TUN
# 子网掩码,这个掩码是VIP的掩码
net_mask 255.255.255.0
# 持久连接超时时间
persistence_timeout 50
# 定义协议
protocol TCP
# 如果后端应用服务器都不可用,就会定向到那个服务器上
sorry_server 192.168.200.200 1358
# 后端应用服务器 IP PORT
real_server 192.168.200.2 1358 {
# 权重
weight 1
# 应用服务器UP或者DOWN,就执行那个脚本
notify_up "这里写的是路径,如果脚本后有参数,整体路径+参数引起来"
notify_down "/PATH/SCRIPTS.sh 参数"
# MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET这些都是
# 针对应用服务器做健康检查的方法
MISC_CHECK {}
# 用于检查SMTP服务器的
SMTP_CHEKC {}
# 如果应用服务器不是WEB服务器,就用TCP_CHECK检查
TCP_CHECK {
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
connect_timeout 3
}
# 如果对方是HTTPS服务器就用SSL_GET方法去检查,里面配置的内容和HTTP_GET一样
SSL_GET {}
# 使用HTTP_GET方法去检查
HTTP_GET {
# 检测URL
url {
# 具体检测哪一个URL
path /testurl/test.jsp
# 检测内容的哈希值,也就是网页的md5值
digest 640205b7b0fc66c1ea91c463fac6334d
# 除了检测哈希值还可以检测状态码,比如HTTP的200 表示正常,两种方法二选一即可
status_code 200
}
url {
path /testurl2/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl3/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334d
}
# 向哪一个端口检查,如果不指定默认使用上面定义的端口
connect_port <PORT>
# 向哪一个IP检测,如果不指定默认使用上面定义的IP地址
bindto <IP>
# 连接超时时间
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
}
}
}
配置Srv01和Srv02
配置VRRP部分
Srv01上的keepalived.conf
global_defs {
notification_email {
acassen@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id srv01
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
}
preempt delay 60
}
Srv02上的keepalived.conf,唯一不同的就是state、priority以及router_id。
global_defs {
notification_email {
acassen@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id srv02
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0
}
preempt delay 60
}
启动2个节点,启动后会自动配置ens33:0这个子接口的虚拟IP
在主节点上你通过systemctl status keepalived
看不到它到底是什么角色,不过在BACKUP节点上你可以看到,但是你在主节点日志中cat /var/log/message
里可以看到Srv01进入到MASTER状态,如下图:
查看Srv02的状态
那么你通过停止Srv01上的keepalived服务就看到MASTER会被转移到Srv02上。
使用该命令查看VRRP通告tcpdum -i ens33 -nn host 224.0.0.18
,你在2台主机都会看到相同的信息。
Srv01使用真实物理IP对该地址进行发送通告,那么Srv02也会收到,如果Srv01宕机,那么Srv02就会使用自己的物理IP向该地址发送通告,由于Srv01已经宕机那么此时Srv02的优先级就是最高的,所以Srv02就变成了MASTER。
配置LVS部分
在keepalived.conf文件中增加下面的内容,2台服务器增加的内容一致,所以这里就写一份。
virtual_server 172.16.42.111 80 {
delay_loop 6
lb_algo rr
lb_kind DR
nat_mask 255.255.255.0
persistence_timeout 0
protocol TCP
sorry_server 192.168.200.200 1358
# 后端应用服务器 IP PORT
real_server 172.16.42.102 80 {
weight 1
# 应用服务器UP或者DOWN,就执行那个脚本
notify_up "/usr/local/notify.sh 172.16.42.102 up"
notify_down "/usr/local/notify.sh 172.16.42.102 down"
HTTP_GET {
# 检测URL
url {
path /index.html
# 除了检测哈希值还可以检测状态码,比如HTTP的200 表示正常,两种方法二选一即可
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
real_server 172.16.42.103 80 {
weight 1
# 应用服务器UP或者DOWN,就执行那个脚本
notify_up "/usr/local/notify.sh 172.16.42.103 up"
notify_down "/usr/local/notify.sh 172.16.42.103 down"
HTTP_GET {
# 检测URL
url {
path /index.html
# 除了检测哈希值还可以检测状态码,比如HTTP的200 表示正常,两种方法二选一即可
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}
这里的notify_up|down脚本我写的很简单就是为了使用一下这个功能,内容如下:
#!/bin/bash
if [ $2 == "up" ]; then
echo "Real server ${1} is UP" > /tmp/notify.txt
elif [ $2 == "down" ]; then
echo "Real server ${1} is DOWN" > /tmp/notify.txt
fi
重启Keepalived服务之后你就可以通过ipvsadm -Ln
查看ipvs规则了,这些规则在2台服务器上都会有,如下图:
测试访问
使用下面的命令快速访问for i in {1..20}; do curl http://172.16.42.111/ | grep "Srv0" --color ; done
可以看到2台服务器交替,因为我们使用的rr调度算法。
故障转移测试
连续访问VIP,然后停止Srv01上面的keepalived服务,这就意味着Srv01也就是失去了VIP,然后观察请求情况以及是否触发之前设定的脚本。
查看Srv02上面的日志
总结
为了提供一个Nginx或者某种后端服务器的负载均衡功能,那么我们需要一个LVS来做调度,但是一台LVS存在单点故障,为了解决LVS单点故障我们使用Keepalived来组建一个LVS的高可用集群。
使用Keepalived构建LVS高可用集群的更多相关文章
- 003.Keepalived搭建LVS高可用集群
一 基础环境 1.1 IP规划 OS:CentOS 6.8 64位 节点类型 IP规划 主机名 类型 主 Director Server eth0:172.24.8.10 DR1 公共IP eth1: ...
- Corosync+Pacemaker+crmsh构建Web高可用集群
一.概述: 1.1 AIS和OpenAIS简介 AIS应用接口规范,是用来定义应用程序接口(API)的开放性规范的集合,这些应用程序作为中间件为应用服务提供一种开放.高移植性的程序接口.是在实现高可用 ...
- nginx+keepalived+consul 实现高可用集群
继 负载均衡 之 nginx+consul+consul template,我这次将使用2台虚拟机,来做一个简单的双机负载均衡试验. 试验目标: 1. 当参加负载均衡的子节点服务,有任何其中一个或多个 ...
- LVS高可用集群
高可用LVS 集群构建 在LVS集群当中Director的作用是很关键的,所以我们在生产环境中要保证其高可用. 高可用架构图: 1.通过 piranha搭建LVS高可用性集群 piranha是REDH ...
- 基于keepalived搭建MySQL高可用集群
MySQL的高可用方案一般有如下几种: keepalived+双主,MHA,MMM,Heartbeat+DRBD,PXC,Galera Cluster 比较常用的是keepalived+双主,MHA和 ...
- keepalived+lvs高可用集群
LVS+Keepalived 介绍 LVS LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国 ...
- LVS高可用集群的配置
网络结构: LVS DR工作原理 LVS集群从客户端上看可以将整个集群看成单个服务器对外提供服务,其IP是集群内部的VIP(虚拟IP).从内部看,转发服务器(DS)其实并没有启动应用层的服务对接口进行 ...
- 【转】Keepalived+Tengine实现高可用集群
原文出处:http://502245466.blog.51cto.com/7559397/1301772 概述 近年来随着Nginx在国内的发展潮流,越来越多的互联网公司使用Nginx:凭Nginx的 ...
- 使用Keepalived实现linux高可用集群
安装 apt install libipset-dev keepalived -y 创建账户 useradd -s/usr/sbin/nologin -M -g root keepalived_scr ...
随机推荐
- 和同门一起做的PHP网站
用的是PHP语言开发,使用ThinkPHP框架,数据库是mysql 统计是用的站长统计,前端很多都是别人网 上扒下来的.css.js水平不高啊.服务器是香港恒创科技的,性价比还可以哦,而且还免备案. ...
- Java核心卷笔记(一)
第三章Java基程序设计结构 1.注释 三种注释方式: // 注释单行 /* 内容 */ 注释单行 /** * 内容 */ 2. java 数据类型 Java数据类型可分为两种:基本数据类型和引用数据 ...
- spring 整合 shiro框架
shiro是用来干嘛的?从它的官网上(http://shiro.apache.org/)基本可以了解到,她主要提供以下功能: (1)Authentication(认证) (2)Authorizatio ...
- Python_重写集合
class Set(object): def __init__(self,data=None): if data == None: self.__data = [] else: if not hasa ...
- 统一流控服务开源-1:场景&业界做法&算法篇
最近团队在搞流量安全控制,为了应对不断增大的流量安全风险.Waf防护能做一下接入端的拦截,但是实际流量会打到整个分布式系统的每一环:Nginx.API网关.RPC服务.MQ消息应用中心.数据库.瞬间的 ...
- 【转】利用 three.js 开发微信小游戏的尝试
前言 这是一次利用 three.js 开发微信小游戏的尝试,并不能算作是教程,只能算是一篇笔记吧. 微信 WeChat 6.6.1 开始引入了微信小游戏,初期上线了一批质量相当不错的小游戏.我在查阅各 ...
- Docker容器发布spring boot项目
一.安装Docker环境 yum install docker 安装完成后,使用下面的命令来启动 docker 服务,并将其设置为开机启动: systemctl start docker.servic ...
- java 保留字段volatile、transient、native、synchronized
1.volatile Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享 ...
- 静态资源压缩(GZIP) 专题
1.开GZIP有什么好处?答:Gzip开启以后会将输出到用户浏览器的数据进行压缩的处理,这样就会减小通过网络传输的数据量,提高浏览的速度.Tips:如果网站的用户分布比较分散,并且静态文件过大,可以将 ...
- oracle中数据类型对应java类型
地址: http://otndnld.Oracle.co.jp/document/products/oracle10g/102/doc_cd/Java.102/B19275-03/datacc.htm ...