搞了几乎一个月的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 ,所以我们会手动去建立这个文件.
====================== 邪恶的分割线 ============================
然后进行 负载均衡和 真是服务器的 规划吧,配置一个集群,肯定需要规划好,否则会乱七八糟的。
以下是我的服务器规划:
PS:这里可以注意到我的真实服务器起了多个服务,占用了不同的端口,但我对外提供期望都是80端口,这个是用iptables做了端口转发的,大家不要奇怪,后面一篇我会再详述。
好的,网络规划好了。
第一步,我们在lvs-primary上配置keepalived 配置,把这些VIP啥的都配上去,我把我的配置贴下出来。大家不要闲多,其实不多,仔细看下就好(我已经删除了很多配置,我自己的还要复杂一点点):
!Configuration File for keepalived virtual_server 192.168.2.212 80 { real_server 192.168.2.220 80 { real_server 192.168.2.221 80 {
#VIP 和对应的真实服务器设置 virtual_server 192.168.2.213 80 { real_server 192.168.2.220 80 { real_server 192.168.2.221 80 { |
上面的配置应该还算比较简单。然后配置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 参数就可以了,哈哈,又搞定了个难题。