linux负载均衡技术lvs

简介

lvs是linux上的一种负载均衡技术。这篇文章简单记录测试和理解。

网络基础

  • 同网段的服务器之间通信,需要先通过arp广播获取对方的MAC地址,然后发送给网络交换机。
  • 跨网段的通信,则是先通过arp获取网关的MAC地址,然后将数据包发送给网关,由网关进行后续转发。
  • ip地址是记录了通信的起点和重点信息,方便记忆和配置;而MAC地址是记录的是下一个接受者的信息,网络设备需要根据这个MAC地址决定应该从哪个网口发送出去。

arp测试

arp一般都是自动工作的,不需要手工配置,手工配置一般是网络层,简化了系统维护工作。

#arp相关命令
arp -n   #查看ip和mac地址对应关系,可以用来排查ip冲突
arp -d xx.xxx.xx.xx  #删除某个arp缓存
tcpdump -e arp host xx.xx.xx.xx  #抓取目的ip或者源ip是xx.xx.xx.xx的arp数据包,并且打印mac地址信息

lvs原理

lvs的通信架构就是客户端发送数据到直连服务器(简写DR),再转到真实服务器(简写RS,一般多台)。
lvs有三种模式:

  • nat:客户端发送数据到DR之后,DR修改数据包的源ip地址和目标ip地址,然后转发给RS,RS处理之后会给DR,DR再回给客户端。nginx也是这种工作模式。由于公网ip数量有限,局域网和互联网的通信也是这种模式,局域网有个路由器连接了互联网和局域网内部的网络,它同时有互联网ip和局域网ip。特点是配置简单,要求低。
  • tun: 隧道模式,就是在基础的数据包外层再封装一层数据包结构。特点是支持跨机房。
  • dr: 客户端发送数据到DR之后,DR修改数据包的MAC地址为真实服务器网卡的MAC地址,不修改数据包的源ip(源IP还是客户端IP),然后发送给RS(RS需要配置与DR相同的ip,这样RS收到数据包就会正常处理),RS处理之后,直接应答给客户端(因为DR发来的数据包的源ip是客户端ip),不需要经过DR。DR是使用最广泛的,因为数据包只有进来的时候需要DR分发给RS,RS返回数据的时候不需要经过DR处理,性能比nat和tun好。DR模式的网络处理瓶颈在于修改进来的网络包MAC,所以如果进来的网络包较小,处理能力就较强。

对于dr模式,需要在RS和DR上面配置同样的ip,那么不会存在ip冲突的问题吗?这个问题就需要上面提到的arp协议知识解答了。如果多台服务器(DR+RS)配置同一个ip(假设为vip),但是只有一个服务器会回应对vip的arp查询(实际就是DR服务器),那么所有到vip的数据包都会发送到这个能正常回应arp查询的服务器,不会发生ip冲突的问题。
为什么需要在RS上面也配置vip呢?因为这样RS收到DR修改了MAC地址的数据包的时候,解析数据包发现目的ip就是自己配置了的vip,就会正常处理并返回数据包;RS应答的数据包的源ip就是vip,目标ip是客户端ip,客户端收到后也能正常处理,形成一个闭环。或者如果RS返回数据包的源ip是其他ip,就会发生客户端问ipx一个问题,忽然收到一个来自ipy的回答,它对应不上来,处理不了。

lvs测试验证

  • 环境准备:
    一台DR,ip为18.1.99.238,两台RS,ip分别为18.1.99.236和18.1.99.237,vip为18.1.99.239,客户端则是任意一个linux服务器
  • RS服务器配置:
    在两台RS上安装nginx,并进行简单配置
[root@18.1.99.236 conf.d]# cat index.conf 
server {
   listen 8080;
   location / {
     return 200 "this is on 236\n";
   }

}
[root@18.1.99.236 conf.d]# cd  /usr/local/nginx/sbin/
[root@18.1.99.236 sbin]# ./nginx 
[root@18.1.99.236 sbin]# curl http://18.1.99.236:8080
this is on 236

[root@18.1.99.237 conf.d]# cat index.conf 
server {
   listen 8080;
   location / {
     return 200 "this is on 237\n";
   }

}
[root@18.1.99.237 conf.d]# cd  /usr/local/nginx/sbin/
[root@18.1.99.237 sbin]# ./nginx 
[root@18.1.99.237 sbin]# curl http://18.1.99.237:8080
this is on 237
  • 网络配置
ipvsadm命令参数
              -A #添加DR
              -D #删除DR
              -L  #显示配置
              -a  #添加RS
              -d  #删除RS
              -t   #tcp协议
              -s  [rr|wrr|dh|sh|..]  #DR分发给RS的策略
              -g #dr模式,默认模式
              -i  #tun模式
              -m #nat模式

#dr配置
[root@18.1.99.238 ~]# cd /etc/sysconfig
[root@18.1.99.238 ~]# touch ipvsadm
[root@18.1.99.238 ~]# systemctl start ipvsadm
[root@18.1.99.238 ~]# ipvsadm -A -t 18.1.99.239:8080 -s rr
[root@18.1.99.238 ~]# ipvsadm -a -t 18.1.99.239:8080 -r 18.1.99.236:8080 -g -w 1
[root@18.1.99.238 ~]# ipvsadm -a -t 18.1.99.239:8080 -r 18.1.99.237:8080 -g -w 1
[root@18.1.99.238 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  18.1.99.239:8080 rr
  -> 18.1.99.236:8080             Route   1      0          0         
  -> 18.1.99.237:8080             Route   1      0          0

#客户端访问测试
curl http://18.1.99.239:8080/
#抓包监控
#DR和RS服务器上同时抓包和监控数据包错误
[root@18.1.99.237 ~]# tcpdump -nn -vv  tcp port 8080
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
19:16:01.154305 IP (tos 0x0, ttl 62, id 55678, offset 0, flags [DF], proto TCP (6), length 60)
    18.1.98.240.54158 > 18.1.99.239.8080: Flags [S], cksum 0xb33c (correct), seq 4057379965, win 29200, options [mss 1460,sackOK,TS val 847014882 ecr 0,nop,wscale 7], length 0
^C
1 packet captured
1 packet received by filter
0 packets dropped by kernel

[root@18.1.99.237 ~]# sar -n EIP 1
Linux 4.18.0-193.el8.x86_64 (18.1.99.237)         04/10/2023      _x86_64_        (4 CPU)

07:15:49 PM ihdrerr/s iadrerr/s iukwnpr/s   idisc/s   odisc/s   onort/s    asmf/s   fragf/s
07:16:00 PM      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
07:16:02 PM      0.00      1.00      0.00      0.00      0.00      0.00      0.00      0.00

[root@18.1.99.100 ~]# arp -n | grep 18.1.99.239
18.1.99.239              ether   00:50:56:b2:74:f4   C                     eth0

#可以发现RS18.1.99.237收到了DR转发过来的数据包
#但是由于RS上面没有配置18.1.99.239,导致网络包错误iadrerr增加,无法正常响应客户端的访问

#所以必须在RS在lo网卡上配置vip18.1.99.239,并且禁止RS响应关于18.1.99.239的arp查询请求
#ens192是我服务器的网卡,根据自己服务器情况设置
sysctl -w net.ipv4.conf.ens192.arp_ignore=1
ifconfig lo:1 18.1.99.239 netmask 255.255.255.255
#这个配置会导致从ens192收到的arp查询的地址如果不是ens192网卡上配置的,
#就不会回应。数据包都是从ens192进来的,vip配置在lo网卡上,所以RS服务器不会回应vip的arp查询请求。
#再次测试,客户端收到并且正常回复

#但是如果客户端也在18.1.99.0/24这个网段(和RS一个网段),还是会出现问题
#测试结果见下面图片arp_announce.png
#观察发现RS的确没有回应客户端的arp查询请求,
#但是RS回包给客户端的时候发现客户端和自己是一个网段的,于是RS通过arp请求查询客户端服务器MAC地址,
#这个arp请求包的源ip是vip,MAC是RS的网卡ens192的MAC地址,客户端收到这个请求之后会更新arp表,将vip和RS网卡ens192的MAC对应上了。
#所以linux上服务器A查询服务器B的MAC可能会触发服务器B的arp表更新

#为了解决这个问题,就需要调整RS系统参数
sysctl -w net.ipv4.conf.ens192.arp_announce=2
#这会导致RS查询客户端MAC的时候arp查询请求包的源ip是ens192网卡的ip,而不是lo网卡上配置的vip(虽然RS是打算使用vip和客户端通信),这样RS查询客户端的MAC地址的时候就不会更新客户端的arp表。

arp_announce.png

总结

想要理解lvs的工作原理,需要了解数据链路层的通信原理,arp协议;在这篇文章中,我通过一步一步添加配置,然后抓包测试,分析缺少配置会发生的问题,有助于深入了解lvs工作原理。其中最重要的是通过tcpdump抓包分析这个过程。
网上关于arp_announce的说明始终有点难以完全理解,但是我通过保持arp_announce为0,进行测试,观察导致的问题之后,就很好理解为什么要设置arp_announce为2了。

参考

posted @ 2023-05-29 10:52  董少奇  阅读(23)  评论(0)    收藏  举报