解决OS虚拟机内采用LVS-DR模式请求超时问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决OS虚拟机内采用LVS-DR模式请求超时问题相关的知识,希望对你有一定的参考价值。

参考技术A

公司大促期间,由于扩容了大量云主机,采用LVS DR模式的Zabbix-Proxy端请求巨增,导致监控数据采集的队列长时间堆积,已经在前端界面无法展示。所以这个时候负责监控的同事从我这里申请了20多台虚拟机用于抗监控流量。

Zabbix-Proxy的集群框架是 Keepalived + lvs ,原本以为只需要给安装Keepavlived的两台虚拟机分配一个Vip就好了 (让虚拟机支持高可用的vrrp协议) ,结果过了一阵监控的同事告诉我vip的端口访问超时,我便开始觉得自己想得太简单。

看下问题现场:

客户端返回内容很简单,连接超时。

LVS端看到问题很明显,客户端请求过来的连接状态全部卡在 SYN_RECV ,说明请求已经到达LVS,但是在丢给后端Real Server的时候处理异常。

那么问题点出在哪儿呢?

最开始怀疑是虚拟机上iptables规则影响DR模式的报文转发,因为DR模式下的LVS在接收到请求后,会将报头拆解,将dst mac改成后端RealServer的MAC地址,然后重新封装好报文通过广播vip地址丢到后端的RealServer处理。

于是我清空所有虚拟机的iptales,并关闭selinux。但问题仍然存在,说明问题不在虚拟机上。

根据LVS DR模式的特性,后端的RealServer上的lo网卡需要绑定vip地址,否则当接受到转发过来 dst ip 为vip的报文时,默认也会丢弃,造成客户端访问超时的问题。

通过和监控的同事沟通,确定排除这块问题,我又想到会不会需要把vip同时也绑定到RealServer上。我再用 allowed_address_pairs 参数更新了后端虚拟机的Port。客户端请求依然超时,说明问题并不是这里。

由于排除了虚拟机问题,我这边将解决问题的重点移至安全组策略。我们知道Neutron通过iptables规则来实现虚拟机进出流量的限制。

于是我将安全组策略全部打开,如下图:

客户端还是超时!!!这个时候我已经感觉无计可施。

转折

过了一会,我觉得应该做最后一搏,于是我将宿主机上iptables全部清空,客户端居然通了!

排查

看来问题点在宿主机上的Iptables,找到这个方向后,我便开始根据VIP对iptables进行反向排查。

Chain neutron-openvswi-o38833ad6-c

上面这一条意思很明确,就是绑定虚拟机IP和MAC地址,只允许MAC地址为 FA:16:3E:C4:20:C7 ,IP地址为 10.1.26.252 和 10.1.26.144 通过,其余DROP掉。 neutron-openvswi-s38833ad6-c 这条Chain是从 neutron-openvswi-o38833ad6-c 跳转下来的。

Chain neutron-openvswi-o38833ad6-c

neutron-openvswi-o38833ad6-c 这条Chain是用于规则虚拟机出口流量,可以看到它是从两条Chian上跳转下来的 neutron-openvswi-INPUT 和 neutron-openvswi-sg-chain 。
neutron-openvswi-o38833ad6-c 主要定义虚拟机engress的安全规则。这里可以看到之前创建的规则已经下发到ipables上应用成功。将没匹配的到规则丢给 neutron-openvswi-sg-fallback ,fallback里面就一条规则,丢弃进来的所有报文。

Chain neutron-openvswi-i38833ad6-c

neutron-openvswi-i38833ad6-c 这条Chain是用于规则虚拟机入口流量,这里看住它只从 neutron-openvswi-sg-chain 上面跳转下来,同时将没匹配的到规则丢给 neutron-openvswi-sg-fallback 。

Chain neutron-openvswi-sg-chain

这里可以看到 neutron-openvswi-sg-chain 处理虚拟机入口和出口流量,同时由 neutron-openvswi-FORWARD 跳转而来。
physdev模块是iptables用于过滤linuxbridge上的网络包,

Chain neutron-openvswi-FORWARD

根据上下文可以确定, neutron-openvswi-FORWARD 是由filter表的 FORWARD 跳转过来。

Chain FORWARD

这里看到报文在转发之前还进入了 neutron-filter-top 链,继续往下。

看到这里我想大部分同学应该明白了,LVS DR模式的虚拟机在转发报文时,默认的FORWARD链里面并没有针对处理报文转发的规则。于是我在 neutron-openvswi-local 加了一条ACCEPT的语句,终于客户端就能正常请求VirtualServer了。

思考

由于LVS的DR模式的特殊性,VirtualServer在收到客户端请求时,并不响应请求,只修改报头重新转发给RealServer。从宏观来看过程并不是VS去请求RS。当请求走到VS所在宿主机上面时,自然会分到FORWARD链上,而这时Netron处理虚拟机iptables时,只做了对虚拟机访问的限制,而当虚拟机需要转发自己数据包时就没有处理规则。从而导致客户端在连接时出现超时的现象。

由于Neutron有基于Haproxy的负载均衡服务,并不鼓励在虚拟机上直接搭建负载均衡器,所以我想在处理这类的问题应该都转到FAAS上面了。总之通过这次排点,对Neutron这块又有了新的认识。

部署LVS-DR + keepalived 高可用群集

  • LVS集群采用IP负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。整个服务器集群的结构对客户是透明的,而且无需修改客户端和服务器端的程序。为此,在设计时需要考虑系统的透明性、可伸缩性、高可用性和易管理性。
  • 直接路由(DirectRouting);简称DR模式,采用半开放式的网络结构,与TUN模式的结构类似,但各节点并不是分散在各地,而是与调度器位于同一个物理网络。负载调度器与各节点服务器通过本地网络连接,不需要建立专用的IP隧道。
  • Keepalived的作用是检测服务器的状态,如果有一台web服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。

  • 实验需求

技术分享图片

服务器主机 IP: ( VIP:192.168.200.100) 需要安装配置
NFS共享服务器 192.168.200.105 NFS共享存储
LVS主调度器 192.168.200.103 keepalived 、ipvsadm
LVS从调度器 192.168.200.104 keepalived 、ipvsadm
节点服务器1 192.168.200.101 httpd 、NFS
节点服务器2 192.168.200.102 httpd 、NFS
windows客户机 192.168.200.200 测试专用
  • LVS调度服务器
  • 主从调度服务器配置基本相同(不同之处已经标注)

    # yum install keepalived ipvsadm -y
  • 调整proc响应参数

    # vi /etc/sysctl.conf     
        net.ipv4.ip_forward=1
        net.ipv4.conf.all.send_redirects = 0
        net.ipv4.conf.default.send_redirects = 0
        net.ipv4.conf.ens33.send_redirects = 0
        //proc响应关闭重定向功能//
        # sysctl -p    //立即生效
  • 配置虚拟VIP

    # cd /etc/sysconfig/network-scripts
    # cp ifcfg-ens33 ifcfg-ens33:0
    # vim  ifcfg-ens33:0
        DEVICE=ens33:0
        ONBOOT=yes
        IPADDR=192.168.200.100
        NETMASK=255.255.255.0
    
    # ifup ens33:0     //启用虚拟IP
  • 配置负载分配策略
  • 编写脚本方便管理

        # cd /etc/init.d/
        # vi dr.sh
            #!/bin/bash
            GW=192.168.200.1
            VIP=192.168.200.100
            RIP1=192.168.200.101
            RIP2=192.168.200.102
            case "$1" in
            start)
                /sbin/ipvsadm --save > /etc/sysconfig/ipvsadm
                systemctl start ipvsadm
                /sbin/ifconfig ens33:0 $VIP broadcast $VIP netmask 255.255.255.255 broadcast $VIP up
                /sbin/route add -host $VIP dev ens33:0
                /sbin/ipvsadm -A -t $VIP:80 -s rr
                /sbin/ipvsadm -a -t $VIP:80 -r $RIP1:80 -g
                /sbin/ipvsadm -a -t $VIP:80 -r $RIP2:80 -g
                echo "ipvsadm starting --------------------[ok]"
                ;;
                stop)
                /sbin/ipvsadm -C
                systemctl stop ipvsadm
                ifconfig ens33:0 down
                route del $VIP
                echo "ipvsamd stoped----------------------[ok]"
                 ;;
                status)
                if [ ! -e /var/lock/subsys/ipvsadm ];then
                echo "ipvsadm stoped---------------"
                exit 1
                                else
                                echo "ipvsamd Runing ---------[ok]"
                fi
                ;;
                *)
                echo "Usage: $0 {start|stop|status}"
                exit 1
                esac
                exit 0
    
        # chmod +x dr.sh
        # service dr.sh start
  • keepalived部署

    # vim /etc/keepalived/keepalived.conf
        global_defs {
    ...
    smtp_server 127.0.0.1           #指向本地
    router_id LVS_01   #指定名称,备份服务器不同名称
    ...             
    }
    vrrp_instance VI_1 {
    state MASTER             #备份服务器是BACKUP
    virtual_router_id 10     # 组号   备份服务器相同
    ...
    auth_pass abc123         #验证密码  备份服务器相同
    priority 100              #优先级  备份小于主
    ...
    virtual_ipaddress {
    192.168.200.100          //指定VIP地址
        }
    ...
    virtual_server 192.168.200.100 80 {
        lb_kind DR            //指定DR模式
    ...
    real_server 192.168.200.101 80 {        #web节点地址端口
    weight 1                         #节点的权重
    TCP_CHECK {               #健康检查方式
        connect_port 80         #添加端口
        connect_timeout 3    #连接超时
        nb_get_retry 3           #重试次数
        delay_before_retry 3   #重试间隔(秒)
    }   
        }   
        real_server 192.168.200.102 80 {
    weight 1
    TCP_CHECK {
        connect_port 80              #添加端口
        connect_timeout 3          
        nb_get_retry 3
        delay_before_retry 3
    }   
        }    
    }
    # systemctl start keepalived 
    # ip addr show dev ens33:0         #查看虚拟网卡
    # systemctl stop firewalld.service   #关防火墙
    # setenforce 0
  • 配置NFS共享服务器

    # systemctl stop firewalld.service   //关防火墙
    # setenforce 0
    # yum install nfs-utils rpcbind -y   //安装NFS服务
    # systemctl start rpcbind.service
    # systemctl start nfs.service  
    # cd /opt | mkdir benet accp  //创建共享目录
    (在实际工作中 还是要共享挂载磁盘阵列raid的目录)
    # vi /etc/exports
        /usr/share *(ro,sync)
        /opt/benet 192.168.200.0/24(rw,sync)            
        /opt/accp 192.168.200.0/24(rw,sync) 
    # exportfs -rv    //发布共享
  • 节点服务器配置
  • 两个节点服务器配置基本相同(不同之处已经标注)

    # yum install nfs-utils rpcbind -y   //安装NFS服务
    # mount.nfs 192.168.200.105:/opt/benet /var/www/html  //挂载NFS
    # yum install -y httpd   #安装httpd服务
    # systemctl start httpd.service      #启动httpd服务
    # systemctl stop firewalld.service    #关防火墙
    # setenforce 0
  • 建立一个测试页面
  • 两个节点服务器测试页面要不同

    # echo "this is 7.1 web" > /var/www/html/index.html    #节点服务器1
    # echo "this is 7.2 web" > /var/www/html/index.html    #节点服务器2 (方便查看测试结果)
  • 配置虚拟VIP
  • 作用:仅发送web响应数据包的源地址

    # cd /etc/sysconfig/network-scripts
    # cp ifcfg-lo ifcfg-lo:0
    # vim ifcfg-lo:0
        DEVICE=lo:0
        IPADDR=192.168.200.100
        NETMASK=255.255.255.0
        ONBOOT=yes
  • 编写服务脚本方便管理
  • 添加VIP本地访问路由
  • 调整proc响应

        # cd /etc/init.d/
        # vim web.sh
                #!/bin/bash
                VIP=192.168.200.100
                case "$1" in
                start)
            ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
            /sbin/route add -host $VIP dev lo:0
            echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
            echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
            echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
            echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
            sysctl -p >/dev/null 2>&1
            echo "RealServer Start OK "
            ;;
                stop)
            ifconfig lo:0 down
            route del $VIP /dev/null 2>&1
            echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
            echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
            echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
            echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
            echo "RealServer Stopd"
            ;;
                *)
            echo "Usage: $0 {start|stop}"
            exit 1
                esac
                exit 0
    
        # chmod +x web.sh
        # service web.sh start
        # ifup lo:0        //启用虚拟VIP
        # firefox "http://127.0.0.1/" &     //火狐查看测试页
        # service web.sh stop
        # service web.sh start    //(建议重启服务)
  • 测试

    在windows7  浏览器输入 虚拟VIP 192.168.200.100 
    (多刷新几次可以看到节点1和节点2的测试页面为成功)

技术分享图片技术分享图片

以上是关于解决OS虚拟机内采用LVS-DR模式请求超时问题的主要内容,如果未能解决你的问题,请参考以下文章

LVS-DR+keepalive做高可用,实现负载均衡(主备模式)

jedis 连接 虚拟机内redis服务

部署LVS-DR + keepalived 高可用群集

如何在vmware虚拟机内设置网卡?

LVS-DR(直接路由模式)配置

lvs-dr模式部署遇到问题,求教老鸟