LVS 配置

搞了几乎一个月的LVS,把遇到的问题记录下,以备后用。如果你也遇到一些问题,也欢迎与我讨论。

 

对LVS的理解:

LVS 我的理解,就是把进来的请求分给后端真是服务器处理,而对客户端来说,只知道一个IP,至于这个IP后面隐藏了多少真实服务器,对客户端来说是透明的。(没那么官方的理解。俺不喜欢搞得太正式)

 

对LVS 的几种调度模式的理解:

NAT:简单理解,就是数据进出都通过LVS,性能不是很好。

TUNL:简单理解:隧道

DR: 简单理解,客户端请求过来通过LVS,LVS转发给真实服务器,真实服务器会直接返回给客户端而通过LVS。性能最好

 

对KeepAlived的理解:

因为所有的请求都要经过负载均衡,所以负载均衡必然是非常重要,不能挂掉,将白了就是要keep the lvs alived。所以 keepalived提供的功能就是可以配置2台LVS,一台主机,一台备机。并且检测任何一个节点是否还活着。

 

以上是个人的一些简要理解,详细的可以看官方网站。

 

安装LVS:

如果是red hat系统默认安装的。我就不多说了

安装LVS的命令行管理软件 ipvsadm

1,上这个网站去下个对应操作系统版本的吧http://www.linuxvirtualserver.org/software/index.html 

我用的是http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz 

2,ln –sv /usr/src/kernels/2.6.18-194.el5-x86_64 /usr/src/linux

3,解包 tar zxvf ipvsadm-1.24

4,cd ipvsadm-1.24; make;make install

 

安装keepalived

1,下载页面:http://www.keepalived.org/download.html

我安装的是 http://www.keepalived.org/software/keepalived-1.1.20.tar.gz

2,解包 tar zxvf keepalived-1.1.20.tar.gz

3,cd keepalived-1.1.17

4,./configure –prefix=/usr/local/keepalive

5,make ; make install

注:keepalived 启动的时候默认去找 /etc/keepalived/keepalived.conf ,所以我们会手动去建立这个文件.

 ====================== 邪恶的分割线 ============================

然后进行 负载均衡和 真是服务器的 规划吧,配置一个集群,肯定需要规划好,否则会乱七八糟的。

以下是我的服务器规划:

 
LVS 配置_第1张图片

 

 

 

PS:这里可以注意到我的真实服务器起了多个服务,占用了不同的端口,但我对外提供期望都是80端口,这个是用iptables做了端口转发的,大家不要奇怪,后面一篇我会再详述。

 

好的,网络规划好了。

第一步,我们在lvs-primary上配置keepalived 配置,把这些VIP啥的都配上去,我把我的配置贴下出来。大家不要闲多,其实不多,仔细看下就好(我已经删除了很多配置,我自己的还要复杂一点点):

 

!Configuration File for keepalived
   
global_defs {
   router_id LVS_DEVEL_1
}       
    #我们的trading应用的同步组(同步组的意思就是一个组内的有一个挂掉的话,组内所有的应用都切换到备机上去)
vrrp_sync_group HZ_A1 {
   group {
       VI_TRADING
   }
}  
    #我们css服务器的同步组
vrrp_sync_group HZ_NGINX {
   group {
       VI_NGINX
   }
}       
       #实例设置
vrrp_instance VI_TRADING {
    state MASTER
    interface eth0
    lvs_sync_daemon_inteface eth2 我这里用另外一张网卡做 负载均衡主备间的同步
    virtual_router_id 220
    priority 200
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }     
              
    virtual_ipaddress {
        192.168.2.212
    }     
}         
           #实例设置
vrrp_instance VI_NGINX {
    state MASTER
    interface eth0
    lvs_sync_daemon_inteface eth2
    virtual_router_id 221
    priority 200
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }     
          
    virtual_ipaddress {
        192.168.2.213
    }
}


#VIP和对应的真实服务器设置

virtual_server 192.168.2.212 80 {
    delay_loop 6 
    lb_algo wlc       #采取权重式的最少链接分配模式
    lb_kind DR        #采取DR模式
    protocol TCP

    real_server 192.168.2.220 80 {
        weight 120
        HTTP_GET {
           url {
               path /index.html
               digest 444bcb3a3fcf8389296c49467f27e1d6     #使用 genhash 做的 HTTP摘要
             }
           connect_timeout 10
           nb_get_retry 3
           delay_before_retry 2
       }
    }

    real_server 192.168.2.221 80 {
        weight 120
        HTTP_GET {
           url {
               path /index.html
               digest 444bcb3a3fcf8389296c49467f27e1d6      #使用 genhash 做的 HTTP摘要
             }
           connect_timeout 10
           nb_get_retry 3
           delay_before_retry 2
       }
    }
}

 

#VIP 和对应的真实服务器设置

virtual_server 192.168.2.213 80 {
    delay_loop 6
    lb_algo wlc
    lb_kind DR
    protocol TCP

    real_server 192.168.2.220 80 {
         TCP_CHECK {   #TCP 检查
               connect_port 4000
               connect_timeout 10
               nb_get_retry 3
               delay_before_retry 3
        }
    }

    real_server 192.168.2.221 80 {
            TCP_CHECK {  #TCP 检查
               connect_port 4000
               connect_timeout 10
               nb_get_retry 3
               delay_before_retry 3
        }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上面的配置应该还算比较简单。然后配置lvs-standby的配置。

这里lvs-standby的配置只需要有3个地方与lvs-primary不同就可以了

1,router_id  不同

2,priority 不同,备的必须比主的低

3,主的为MASTER, 备的为BACKUP

 

其他可以根据需要不同,基本上没什么特殊需要,就都不用改了。

 

------------------------ 邪恶的分割线 -------------------------

负载均衡配置好了,我们开始配置 真实服务器。

我在真实服务器上搞两个脚本来配置,脚本很简单 lvs_real.sh:

#!/bin/bash
#description : start realserver
VIP1=192.168.2.212
VIP2=192.168.2.213
/etc/rc.d/init.d/functions
case "$1" in
start)
echo " start LVS of REALServer"
/sbin/ifconfig lo:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up
/sbin/ifconfig lo:1 $VIP2 broadcast $VIP2 netmask 255.255.255.255 up
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
;;
stop)
/sbin/ifconfig lo:0 down
/sbin/ifconfig lo:1 down
echo "close LVS Directorserver"
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 "Usage: $0 {start|stop}"
exit 1
esac

 运行 lvs_real.sh start 就全都设置好了。

 

到此为止,就可以启动keepalived了。不知道参数怎么加,可以用-help。

我就讲下比较难理解的几个参数:

--dont-release-vrrp  当keepalived进程被kill后不修改 "ip add"  中的inet设置。讲白了。保留了VIP的绑定

--dont-release-ipvs  当keepalived进程被kill后不清空 lvs 的连接table ,继续让 LVS 提供服务。讲白了,保留了ipvs 的 转发规则的table

 

重要:如果期望keepalived被kill掉以后,我们的转发还能继续,那么就加上这2个参数,但是,如果你是主备模式的,千万不要加这两个参数,否则备机发现主的keepalived已经关掉了,就会把自己变成主的,绑定上VIP,这样其实就有IP冲突了啊!!!

 

到此为止,如果你的环境没那么复杂的话,就可算配置完成,可以运行了。但我的环境是比较复杂的,于是我还得继续描述下去。

 

 好了,我来说我的第一个问题(上面贴的网络规划图上已经标注):

lvs-primary,lvs-standby互相不认识,都开始抢VIP的绑定,并且/var/log/messages不断报错。

May  5 03:09:36 lvs-primary avahi-daemon[4627]: Host name conflict, retrying with <lvs-primary-15>
May  5 03:09:36 lvs-primary avahi-daemon[4627]: Registering new address record for fe80::7a2b:cbff:fe13:8e1 on eth2.
May  5 03:09:36 lvs-primary avahi-daemon[4627]: Registering new address record for 192.168.3.210 on eth2.
May  5 03:09:36 lvs-primary avahi-daemon[4627]: Registering new address record for fe80::7a2b:cbff:fe13:8dd on eth0.
May  5 03:09:36 lvs-primary avahi-daemon[4627]: Registering new address record for 192.168.2.212 on eth0.
May  5 03:09:36 lvs-primary avahi-daemon[4627]: Registering new address record for 192.168.2.210 on eth0.
May  5 03:09:36 lvs-primary 

具体现象可以在主 ,备机上 都使用 ip add 查看,应该是都有 VIP。

 

分析原因:主的机器应是理所当然有VIP的,那么备的为什么也有VIP呢。备的会有VIP的原因只可能是他认为主的不存在或者挂了,他要接替主的位置。 那么主的明明存在。

至此,我想,你也肯定猜测 主备 之间的"心灵感应"没有了。没错,正如你所猜测的!

是谁,这么残忍的将这对“情侣”分开!!!

没错,又正如你所猜测的,iptables!!!

因为keepalived 主备间通信的话需要进行组播

如果是这样的话,需要加入iptables规则(编辑 /etc/sysconfig/iptables):

-A INPUT -d 224.0.0.0/255.0.0.0 -j ACCEPT  (当然如果你能更精确的控制更安全,这个规则比较笼统)

 加上了这条规则以后,我的问题貌似得到了解决。

 

可惜,事实并不是那么简单。上面的问题还在继续报。无奈之下求助了我们的架构师。架构师给了我建议:在主备服务器上也加上下面的配置:

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

神乎其技般,问题解决了。 虽然我还是没弄懂到底什么原因。 仰视我们的架构师!

 

接下来,遇到的问题2:

现象是这样的,我用apache 的ab去做压力测试。类似 20W个请求,500个并发的去压一个页面,不一会apache 的ab就开始报错了。然后查看 ipvsadm -ln 发现 ActiveConn的特别多,大概接近3W个。但是明明客户端请求玩之后久断开的,真正的TCP链接不会那么多。后面再去用ab压,就怎么也不成功了,除非等好久一段时间。

经查,又是iptables惹的祸,是我们的网络工程师把iptables配置得太严格了,80 端口进来的 ,限制了只有NEW的才能ACCEPT,后面我修改了下,去掉了这个NEW状态的限制(由于我对iptables不太熟悉,搞了大半天都没搞出来,很久才试出来)。

 

还遇到的问题3:

这个问题更另我们头痛了,DELL R710和DELL R910机器的网卡驱动有问题!!!

 

1. rpm -ivh resource_5342237_1278927056x.rpm

2. cd /usr/src/redhat/SPECS/

3. rpmbuild -bb netxtreme2.spec

4. cd ../RPMS/x86_64

5. rpm -ivh netxtreme2-5.2.55-1.x86_64.rpm

 

验证:

modinfo bnx2

 

还原:

rpm -e netxtreme2 

 

 

 

=====================   到此,几乎所有遇到的问题都解决了 ==================

 

后面就是关于LINUX 系统优化的一些参数

在负载均衡的机器上的 /etc/sysctl.conf

 

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_max_syn_backlog = 8192

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_keepalive_time = 1800

net.ipv4.tcp_fin_timeout = 30

net.core.rmem_max = 16777216

net.core.wmem_max = 16777216

net.ipv4.tcp_rmem = 4096 87380 16777216

net.ipv4.tcp_wmem = 4096 65536 16777216

net.core.netdev_max_backlog = 3000

net.ipv4.conf.lo.arp_ignore = 1

net.ipv4.conf.lo.arp_announce = 2

net.ipv4.conf.all.arp_ignore = 1

net.ipv4.conf.all.arp_announce = 2

vm.swappiness = 10

 

真实服务器上的/etc/sysctl.conf

 

 

# Controls the use of TCP syncookies

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_max_syn_backlog = 4096

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

vm.swappiness = 10

 

编辑所有机器上的/etc/security/limits.conf  增加最大文件句柄数:

 

*                soft    nofile          102400

*                hard    nofile          102400

 

-----------------------------  最后,我觉得iptables还是比较容易出错,我贴下出来,以备后面查阅 ----------------

负载均衡上:

# Generated by iptables-save v1.3.5 on Tue May 31 17:54:18 2011
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [503914:50613198]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT 
-A FORWARD -j RH-Firewall-1-INPUT 
-A RH-Firewall-1-INPUT -i lo -j ACCEPT 
-A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT 
-A RH-Firewall-1-INPUT -p esp -j ACCEPT 
-A RH-Firewall-1-INPUT -p ah -j ACCEPT 
-A RH-Firewall-1-INPUT -s 192.168.2.211 -d 224.0.0.0/255.0.0.0 -j ACCEPT #这条规则用于主备间心跳
-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp --dport 5353 -j ACCEPT 
-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT 
-A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 22 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m tcp -m multiport --dports 80,12000,8081 -j ACCEPT 
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited 
COMMIT
# Completed on Tue May 31 17:54:18 2011

 

真实服务器上:

# Generated by iptables-save v1.3.5 on Tue May 31 18:07:33 2011

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [3994632801:5999312861198]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT 
-A FORWARD -j RH-Firewall-1-INPUT 
-A RH-Firewall-1-INPUT -i lo -j ACCEPT 
-A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT 
-A RH-Firewall-1-INPUT -p esp -j ACCEPT 
-A RH-Firewall-1-INPUT -p ah -j ACCEPT 
-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp --dport 5353 -j ACCEPT 
-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT 
-A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 8081 -j ACCEPT 
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 4000 -j ACCEPT 
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited 
COMMIT
# Completed on Tue May 31 18:07:33 2011
# Generated by iptables-save v1.3.5 on Tue May 31 18:07:33 2011
*nat
:PREROUTING ACCEPT [157415951:9504623717]
:POSTROUTING ACCEPT [11795947:709220130]
:OUTPUT ACCEPT [11795947:709220130]
-A PREROUTING -d 192.168.2.213 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 4000 
COMMIT
# Completed on Tue May 31 18:07:33 2011
 

 

 

 

=====================  另外,LVS默认安装的hashtable 的size 不是很大========

解决方案,重新编译内核,修改hash table 的size ,使得查找链接的时候冲突减小,命中率提高来提高效率。

 1,下载 LINUX源码:

ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/SRPMS/kernel-2.6.18-194.el5.src.rpm

2,rpm -ivh kernel-2.6.18-194.el5.src.rpm

3,ln -s /usr/src/redhat/BUILD/kerner-2.6.18/linux-2.6.18 linux (如果安装过ipvsadm 的话,应该已经创建过了,这里要把原来的删掉,重新建一个)

4,安装http://mirror.centos.org/centos/5/os/x86_64/CentOS/unifdef-1.171-5.fc6.x86_64.rpm

5,cd /usr/src/linux ,然后make menuconfig ,这里首先加载/boot/configxxxx,这个配置文件,然后再改下 virtual server当中的table size ,我设置为了19

6,make && make modules_install && make install

 

编译好后,改下/boot/grub/menu.lst 中的default = 0

最后reboot就可以了

编译内核部分主要参考了:

http://hi.baidu.com/dekar/blog/item/3428ac255809980f908f9d40.html/cmtid/636f994cad4a3307b3de053b

我写的就比较粗,实在太累了,详细他写的吧。

 

好了,又很晚了,我得早点睡,养足精神好奋战!

 

===========================================

补充 健康检查 MISC_CHECK 部分:

我遇到的情况,底层服务器用的是IIS ,靠域名来解析到不同的应用,而LVS健康检查的HTTP_GET 也是用IP的,这样健康检查不起作用,所以需要用 MISC_CHECK,自己写脚本来实现。脚本如下:

 

#!/bin/bash
SERVER=$1
OK=`curl -s -H "Host: sys.esunny.com" http://$SERVER/monitor.html | grep "<body>OK</body>"`
echo $OK
if [ "$OK" == "" ] ; then
    exit 1;
else
    exit 0;
fi

 

KEEPALIVED配置如下 (注意,脚本一定要加双引号)

real_server 192.168.2.24 80 {
        weight 120
        MISC_CHECK {
           misc_path "/etc/keepalived/sysesunnycheck.sh 192.168.2.24"
        }
    }
 

注意 curl -H 参数就可以了,哈哈,又搞定了个难题。

 

 

 

 

你可能感兴趣的:(.net)