<服务>ARP协议和LVS服务
目录:
ARP协议
ARP协议,地址解析协议,使用ARP协议可以实现通过IP地址获得对应主机的物理地址(MAC地址),在keepalive和lvs中使用广泛。 在TCP/IP协议上,每个联网主机都会通过IP地址进行标识,为逻辑地址,不过为了让报文在物理网路上传输还必须知道物理地址,ARP协议就是为了解决这一问题而生。 ARP协议要求通信的主机双方必须在同一物理网段(即局域网环境)
ARP协议工作原理
例如192.168.0.101想要发送数据给192.168.0.102。
- 192.168.0.101先检查本地缓存的ARP表,检查ARP表中是否有192.168.0.102的MAC地址
- 发送ARP广播,在这一局域网的所有主机都能收到广播
- 主机收到广播进行判断,192.168.0.102收到192.168.0.101广播后进行单播回应本机MAC地址,并缓存192.168.0.101的MAC地址,而其他主机不进行回应
- 192.168.0.101缓存192.168.0.102的MAC地址,并发送数据与192.168.0.102通信
广播的多了就会产生广播风暴,索引就有了vlan进行隔离,当然我们并不是介绍这些。博主对网络研究的也不太好,希望过年回家可以静下心来补习一下大学的计算机网络
查看ARP缓存
[root@why ~]# arp -a
? (121.42.39.247) at 00:00:0c:9f:f3:88 [ether] on eth1
? (10.163.255.247) at 00:00:0c:9f:f2:c0 [ether] on eth0
ARP缓存的优劣势
ARP缓存表可以加快ARP的解析速度,减少广播风暴的产生。 ARP缓存表也给了黑客攻击的机会,例如ARP欺骗
为什么要使用ARP协议
OSI模型把网络工作分为七层,彼此不直接打交道,只通过接口。IP地址工作在第三层,而MAC地址工作在第二层,当协议在发送数据包的时候,需要先封装第三层IP地址,第二层MAC地址的报头,但是协议只知道IP地址,不知道MAC地址,不能跨第二层和第三层进行通信,就需要使用ARP协议。 而ARP是三层协议,从IP地址解析为MAC地址
ARP会遇到的问题的解决办法
- ARP欺骗,在局域网常见,ARP欺骗的原理,是伪造IP地址和MAC地址对实现,能够在网络中产生大量的ARP通信量,以至于网络堵塞,攻击者只需要持续不断的发送伪造的ARP响应包就能改变局域网中目标主机ARP缓存,造成内网内其他计算机的通信故障,如果把网关的ARP缓存修改,就会造成无法访问外网。
- 高可用服务器对切换时要考虑ARP缓存的问题
- 办公室更换路由器访问慢,需要清空ARP缓存
ARP广播更新新的地址解析
/sbin/arping -I eth0 -c 3 -s 192.168.0.103 192.168.0.254
/sbin/arping -U -I eth0 192.168.0.103
负载均衡
负载均衡的软件
lvs,nginx,haproxy,lighttpd 而负载均衡的服务器高可用通过keepalive,heartbeat实现
负载均衡的作用
- 分担用户访问请求数据流量
- 保持7*24小时服务
LVS
LVS全称为Linux Virtual Server,即linux虚拟服务器集群系统。 LVS分为两部分,IPVS工作于Kernel层实现调度,没有人能进行访问,ipvsadm在程序层来管理IPVS,当然也可以通过系统调用来管理IPVS,例如keepalive。
LVS术语
名称 | 名称 | 说明 |
---|---|---|
虚拟IP地址 | VIP | 用于向计算机提供服务的IP地址,查看一个网站的路由显示的IP就是VIP |
真实IP地址 | RIP | 在负载均衡集群上使用的IP地址,访问请求通过VIP转发到RIP |
Director的IP地址 | DIP | 用于连接内外网络的IP地址,是负载均衡器上的IP |
客户端主机IP地址 | CIP | 客户端请求服务器的IP地址,该地址用作发送给集群的请求的源IP地址 |
LVS的常用模式
- NAT模式
- TUN模式
- DR模式
- FULLNAT模式
NAT模式
NAT模式将请求报文发送给真实服务器,而真是服务器将相应后的处理结果返回给负载均衡器,由其返回给客户端用户
NAT模式的原理
客户端发送CIP:VIP的数据包,VIP的服务器接收到CIP:VIP的数据包,会把VIP改为真实服务器的IP,数据包会变为CIP:RIP1,发送给DIP1真实服务器进行解析,处理,因为真实服务器的网关为LVS的IP,所以返回数据包RIP1:CIP经过LVS,把数据包改为VIP:CIP,交给路由器返回给客户端用户
NAT模式特点
- NAT将请求报文和响应报文通过调度器地址重写然后转发到内部的服务器,报文返回时再改写成原来的用户请求的地址
- 只需要在调度器LB上配置公网IP,调度器也要有私有LAN IP和内部RS节点通信
- 内部RS节点的网关地址必须配置成调度器LB的私有LAN内物理网卡地址
- 由于请求与相应的数据报文都经过调度器LB,因此网站访问大的时会有较大的瓶颈,一般为10~20台
- NAT模式支持对IP和端口的转换,即用户请求192.168.0.101:80可以调度为192.168.0.102:8000,这是NAT和TUN模式不具备的
- 所有RS节点只需要有私有LAN IP即可
- 主要开启内核转发,net.ipv4.ip_forward = 1和iptables防火墙的forward功能
TUNNEL模式
TUNNEL模式把数据包前端加一个IP头,再次封装,然后数据包发送给IP头的IP进行解析,处理并返回处理结果直接返回给用户。
与DR模式类似,也需要做绑定VIP并且抑制ARP,不推荐这个方式,所以不过多介绍,参考下边的DR模式
TUNNEL模式的特点
- 负载均衡器通过把请求的报文通过IP隧道(ipip隧道)把请求的报文不经过原目的地址改写直接封装成另外的IP报文
- 调度器LB只做入站请求,吞吐量高,但是因为有隧道的系统开销,会比DR模式慢,不过适合广域网的模式
- LAN环境会采用DR模式,WAN环境采用TUN模式,不过更多的会被haproxy/nginx取代
DR模式
DR模式(直接路由也称单臂路由模式)改写请求报文的目标MAC地址,将请求发给真实服务器,而真实服务器将响应后的处理结果直接返回给客户端用户。
这么做的好处是负载均衡器的压力会小很多
DR模式的原理
客户端发送的CIP:VIP的数据包,VIP的服务器接收到CIP:VIP的数据包,把VIP对应的MAC地址解析到真实的服务器上进行处理即可,但是真实的服务器上没有VIP的IP地址,无法解析包,就需要做绑定VIP地址,这么做会造成两个问题,一方面整个网络中会有多个相同的VIP,会造成冲突,解决的方式就是把VIP绑定到LO(本地环路)接口上,另一方面,ARP协议的ARP广播会使所有的绑定VIP的主机竞争这一数据包,解决的方式是在真实的服务器上抑制ARP,然后真实的服务器上就能进行数据包的解析并处理请求,返回一个VIP:CIP的包直接通过网关返回给CIP,即客户端主机。
DR模式的特点
- 通过调度器LB上修改数据包的目的MAC地址实现转发,源IP地址仍是CIP,目的IP地址认识VIP
- 请求的报文经过调度器,而RS节点(真实服务器)响应处理后的报文无需经过调度器LB,因此并发量大时使用效率很高
- DR模式通过MAC地址的改写机制实现的转发,因此,RS节点和调度器LB必须在同一局域网LAN中
- 需要注意的RS节点默认网关不需要是调度器LB的DIP,而直接是例如IDC机房分配的上级路由的IP,RS可以出网即可,不是不需要配置外网IP
- 调度器LB无法改变请求报文的目的端口
- 如果有多个VIP,需要绑定多个VIP
- 调度器LB可以是UNIX/Linux系统,不支持windows系统,而RS节点可以是windows系统
- DR模式效率高,但是配置麻烦,如果访问量不高可以用haproxy/nginx取代,2000W PV或1w并发一下都可以考虑haproxy/nginx模式。
- 直接对外的web服务最好是用外网的IP地址
FULLNAT模式
FULLNAT模式与NAT模式类似,但是它会把数据包的CIP:VIP都进行修改,例如改为AIP:RIP1,在处理完返回到AIP一个其他的负载均衡服务器,把数据包转化为VIP:CIP的数据包返回给客户端用户,这个AIP能够得知CIP是因为多台负载均衡组通过session表等功能实现的一致性,只有淘宝再用,就不过多解释
LVS调度算法
LVS的调度算法决定了节点之间如何分配工作负荷。
- 固定调度算法:rr,wrr,dh,sh
- 动态调度算法:wlc,lc,lblc,lblcr,SED,NQ
- 常用调度算法:rr,wrr和wlc
算法 | 说明 |
---|---|
rr | 轮询调度,将请求依次发送给不同的RS节点,适合节点处理性能相差不大的情况 |
wrr | 加权轮询调度,根据RS节点的权值分配任务,权重值较高的RS优先获取请求,并且获得更多的任务数 |
dh | 目的地址hash调度,以目的地址为关键字通过hash表查找获得RS地址 |
sh | 源地址hash调度,以目的地址为关键字通过hash表查找获得RS地址 |
wlc | 加权最小连接数调度,根据当前连接数/权重值的最小的进行分配任务,即为动态调度,不过效率较静态的调度算法低 |
lc | 最小连接数调度,新连接直接发送给当前请求连接数最小的RS |
lblc | 基于地址的最小连接数 |
lblcr | 基于地址带重复最小连接数 |
SED | 最短的期望延迟 |
NQ | 最少队列调度 |
LVS配置
配置通过三台主机实现,IP分别为192.168.0.201,192.168.0.202和192.168.0.203,VIP为192.168.0.204
查看内核版本
[root@why-1 ~]# uname -r
2.6.32-431.el6.x86_64
查看内核模块
[root@why-1 ~]# lsmod | grep ip_vs
因为LVS基于内核,需要创建一个链接
[root@why-1 ~]# ln -s /usr/src/kernels/2.6.32-431.el6.x86_64/ /usr/src/linux
[root@why-1 ~]# ll !$
ll /usr/src/linux
lrwxrwxrwx 1 root root 39 1月 14 08:38 /usr/src/linux -> /usr/src/kernels/2.6.32-431.el6.x86_64/
如果没有这个路径目录与核版本号一直如果没有这个路径,需要yum install -y kernel-devel
[root@why-1 yum.repos.d]# yum install -y libnl* popt*
Loaded plugins: product-id, refresh-packagekit, security, subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Setting up Install Process
Package libnl-devel-1.1.4-2.el6.x86_64 already installed and latest version
Package libnl-1.1.4-2.el6.x86_64 already installed and latest version
Package libnl3-doc-3.2.21-8.el6.x86_64 already installed and latest version
Package libnl3-3.2.21-8.el6.x86_64 already installed and latest version
Package libnl3-cli-3.2.21-8.el6.x86_64 already installed and latest version
Package libnl3-devel-3.2.21-8.el6.x86_64 already installed and latest version
Package popt-devel-1.13-7.el6.x86_64 already installed and latest version
Package popt-static-1.13-7.el6.x86_64 already installed and latest version
Package popt-1.13-7.el6.x86_64 already installed and latest version
Nothing to do
[root@why-1 ~]# wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.26.tar.gz
[root@why-1 ~]# tar xf ipvsadm-1.26.tar.gz
[root@why-1 ~]# cd ipvsadm-1.26
[root@why-1 ipvsadm-1.26]# make
[root@why-1 ipvsadm-1.26]# make install
[root@why-1 ipvsadm-1.26]# lsmod | grep ip_vs
加载ip_vs模块到内核,也可以用/sbin/ipvsadm
[root@why-1 ipvsadm-1.26]# modprobe ip_vs
[root@why-1 ipvsadm-1.26]# lsmod | grep ip_vs
ip_vs 125220 0
libcrc32c 1246 1 ip_vs
ipv6 317340 30 ip_vs,ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6
配置虚拟IP
[root@why-1 ~]# ifconfig eth0:0 192.168.0.204 up
[root@why-1 ~]# route add -host 192.168.0.204 dev eth0:0
清空所有
[root@why-1 ipvsadm-1.26]# ipvsadm -C
设置超时时间,分别为TCP,TCPfin和UDP
[root@why-1 ipvsadm-1.26]# ipvsadm --set 30 5 60
-A添加主机,-t指定主机和端口,-s指定算法,-p指定会话保持时间
[root@why-1 ipvsadm-1.26]# ipvsadm -A -t 192.168.0.204:80 -s rr -p 20
-a添加RS,-r指定RSip,-g指定为DR模式,-i和-m分别对应TUNNEL和NAT模式,-w权重
[root@why-1 ipvsadm-1.26]# ipvsadm -a -t 192.168.0.204:80 -r 192.168.0.202 -g -w 1
[root@why-1 ipvsadm-1.26]# ipvsadm -a -t 192.168.0.204:80 -r 192.168.0.203 -g -w 1
[root@why-1 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.0.204:80 rr persistent 20
-> 192.168.0.202:80 Route 1 0 0
-> 192.168.0.203:80 Route 1 0 0
删除RS和VIP等过程,仅供参考,详细的参见--help
[root@why-1 ipvsadm-1.26]# ipvsadm -d -t 192.168.0.204:80 -r 192.168.0.203
[root@why-1 ipvsadm-1.26]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.0.204:80 rr persistent 20
-> 192.168.0.204:80 Route 1 0 0
[root@why-1 ipvsadm-1.26]# ipvsadm -D -t 192.168.0.204:80
[root@why-1 ipvsadm-1.26]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
RS配置
将环路接口绑定到VIP本身,并通过子网掩码为255.255.255.255广播自身。
[root@why-2 ~]# ifconfig lo:0 192.168.0.204/32 up
[root@why-2 ~]# route add -host 192.168.0.204 dev lo
[root@why-2 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.0.204 0.0.0.0 255.255.255.255 UH 0 0 0 lo
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 eth0
抑制ARP
[root@why-2 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@why-2 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@why-2 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
[root@why-2 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
由于浏览器缓存以及LVS默认的回话保持等影响,个人检测的话,会造成总是访问一个的情况,可能需要多次并且间隔一定时间访问才能测试出来,也可以尝试使用不同的浏览器进行测试
[root@why-1 ~]# ipvsadm -L -n --stats
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes
-> RemoteAddress:Port
TCP 192.168.0.204:80 2 2 0 104 0
-> 192.168.0.202:80 1 1 0 52 0
-> 192.168.0.203:80 1 1 0 52 0
arp_ignore配置详解
定义对目标地址为本地IP的ARP询问不同的应答模式
- 0(默认值),回应任何网络接口上任何本地IP地址的ARP请求
- 1只回答目标IP地址是来访问网络接口本地地址的ARP查询请求
- 2只回答目标IP地址是来访问网络接口本地地址的ARP查询请求,且来访IP必须在该网络接口的子网段内
- 3不回应该网络界面的ARP请求,而且只对设置的唯一值和连接地址做出回应
- 4~7保留未使用
- 8不回应所有的本地地址的ARP查询
我们设置为1,也就是只有接网线的本地IP地址进行ARP应答,而我们配置的lo本地环路的接口不做应答,从而抑制了ARP,也就抑制了这个环路IP对VIP数据包的抢占
arp_announce配置详解
对网络接口上,本地IP地址的发送的ARP请求进行回应,并作出相应级别的限制,通过不用的限制,宣布对来自本地源IP地址发出ARP请求的接口
- 0(默认值)在任意网络接口上(eth0,eth1,lo等)上的任何本地地址
- 1尽量避免不在该网络接口的子网端的本地地址作出ARP回应,当发起ARP请求的源IP地址是被设置应该经由路由达到此网络接口的时候很有用,此时会检查来访IP是否为所有接口上的子网段内IP之一,如果该来访IP不属于各个网络接口上的子网段内,那么将采用级别2的方式进行处理
- 2对查询目标使用最适当的本地地址,在此模式下将忽略这个IP数据包的源地址并尝试选择能与该地址进行通信的本地地址,首要是选择所有的网络接口的子网中外出访问子网中包含该IP地址的本地地址,如果没有合适的地址被发现,将选择当前的发送的网络接口或其他的有可能接收到该ARP回应的网络接口来进行发送,限制了使用本地的VIP地址作为优先的网络接口
LVS出现的问题解决思路
- 调度器LB上的LVS规则及IP正确性检查
- RS节点上的VIP绑定和ARP抑制的检查,对VIP做实时监测,出了问题自动处理,或者把lo:0配置成配置文件lo:0
- 在多个LB进行调度的时候,不要轻易停止ARP的抑制
- 可以按照通信方式对client到LB,LB到RS和client到LB进行排查
LVS集群分发请求不均的原因
- LVS的-p参数指定的时长
- LVS调度算法设置
- 后端RS节点的回话保持,例如apache和nginx中配置keepalive参数
- 访问量较少
- 用户请求时间的长短,和请求资源多少大小 一般是由于会话保持导致的,最好是通过cookie和session来做。
LVS高可用解决方案
- 脚本解决,通过LB的脚本,RS脚本,判断RS是否正常工作和HA高可用脚本实现
- Hreadbeat+LVS+Ldirectord,官方链接http://www.linuxvirtualserver.org/docs/ha/heartbeat_ldirectord.html
- Keepalived+LVS,官方链接http://www.linuxvirtualserver.org/docs/ha/keepalived.html
- Piranhalvs Redhat提供的解决方法,不了解具体情况
shell脚本
lvs启动和关闭脚本
[root@why-1 ~]# cat lvs.sh
#!/bin/bash
. /etc/init.d/functions
VIP=192.168.0.204
PORT=80
RIP=(192.168.0.202 192.168.0.203)
start(){
ifconfig eth0:0 $VIP/24 up
ipvsadm -C
ipvsadm --set 30 5 60
ipvsadm -A -t $VIP:$PORT -s rr -p 300
for ((i=0;i<${#RIP[*]};i++))
do
ipvsadm -a -t $VIP:$PORT -r ${RIP[$i]} -g -w 1
done
}
stop(){
ifconfig eth0:0 $VIP/24 down
ipvsadm -C
}
case "$1" in
start)
start
if [ $? -eq 0 ];
then
action "start lvs" /bin/true
else
action "start lvs" /bin/false
fi
;;
stop)
stop
if [ $? -eq 0 ];
then
action "stop lvs" /bin/true
else
action "stop lvs" /bin/false
fi
;;
restart)
start && stop
if [ $? -eq 0 ];
then
action "restart lvs" /bin/true
else
action "restart lvs" /bin/false
fi
;;
*)
echo "USAGE:$0 {start|stop|restart}"
esac
脚本效果
[root@why-1 ~]# ./lvs.sh start
start lvs [确定]
[root@why-1 ~]# ./lvs.sh stop
stop lvs [确定]
[root@why-1 ~]# ./lvs.sh reload
USAGE:./lvs.sh {start|stop|restart}
判定后端RS服务是否正常运行,并进行剔除或加入LVS
[root@why-1 ~]# cat lvscheck.sh
#!/bin/bash
rs_1=192.168.0.202
rs_2=192.168.0.203
vip=192.168.0.204
. /etc/init.d/functions
function web_result {
rs=`curl -I -s $1|awk 'NR==1{print $2}'`
return $rs
}
function lvs_result {
rs=`ipvsadm -ln|grep $1:80|wc -l`
return $rs
}
function auto_lvs {
web_result $1
a=$?
lvs_result $1
b=$?
if [ $a -ne 200 ] && [ $b -ge 1 ]
then
ipvsadm -d -t $vip:80 -r $1 && \
action "kick $1" /bin/true
fi
if [ $a -eq 200 ] && [ $b -lt 1 ]
then
ipvsadm -a -t $vip:80 -r $1 -g -w 1 && \
action "add $1" /bin/true
fi
}
while true
do
auto_lvs $rs_1
auto_lvs $rs_2
sleep 2
done
脚本效果
[root@why-1 ~]# sh lvscheck.sh
kick 192.168.0.202 [确定]#202nginx关闭
kick 192.168.0.203 [确定]#203nginx关闭
add 192.168.0.203 [确定]#203nginx启动
add 192.168.0.202 [确定]#202nginx启动