提到负载均衡,基本任何一个访问大点的网站都会用到,负载均衡的意义就不说了。现在的负载均衡无非是两种实现,一种是TCP层的负载均衡,一种是HTTP层的负载均衡,TCP四层负载均衡比HTTP 七层负载均衡性能强N倍,但是它运行在TCP层自然没办法对HTTP请求进行匹配、转发等操作,还有一个缺点是,TCP负载均衡的后端可能没法直接拿到HTTP请求的源IP。
市面上四层负载均衡有LVS,七层负载均衡有Haproxy、Nginx,目前用的最多的就是这三种了。
一开始我们也用Haproxy,后来发现,qps 到几万的时候会把Haproxy 机器的单核CPU打满,造成访问延迟很大,这是因为Haproxy 是单核驱动的,所以我们放弃Haproxy了。
剩下LVS 和 Nginx了, LVS具有极高的转发性能,而Nginx也是性能极高的Web服务器,如果我们只用LVS,就没法对HTTP请求做转发处理,如果只用Nginx,频繁修改Nginx配置 即使是reload在大流量下也可能会影响请求的正常处理。所以我们一起用了,即:
请求 —> 网络 —> LVS集群 —> Nginx 集群 —> APP
来看一下用什么LVS的什么模式比较好,我了解的人一般用DR 和 NAT两种模式:
DR和NAT都不够好,我觉得最好的是FULLNAT模式,配合OSPF,就组成了LVS+OSPF+FULLNAT集群,棒死了。
先简单说下OSPF,抄下小米博客(http://noops.me/?p=974,很好的文章,可以参考,LVS用的是DR模式)的架构图:
好处有:
1). LVS调度机自由伸缩,横向线性扩展(最多机器数受限于三层设备允许的等价路由数目 maximum load-balancing );
2). LVS机器同时工作,不存在备机,提高利用率;
3). 做到了真正的高可用,某台LVS机器宕机后,不会影响服务(但因为华3设备ospfd调度算法的问题,一台宕机会使所有的长连接的断开重连,目前还无法解决;思科的设备已经支持一至性哈希算法,不会出现这个问题)。这里不说三层设备的OSPF配置和LVS机器的OSPF配置了,参考小米博客吧,哈哈哈。
小米博客中用到的是DR模式,我们用到的是FULLNAT模式,FULLNAT模式要重编LVS机器内核,这里说说如何重编。
1). 准备环境
yum -y install m4 gcc redhat-rpm-config xmlto asciidoc elfutils-libelf-devel binutils-devel newt-devel perl-ExtUtils-Embed hmaccalc rng-tools python-devel openssl openssl-devel popt-devel
2). 拿到源码
cd /home/op/
wget ftp://ftp.redhat.com/pub/redhat/linux/enterprise/6Server/en/os/SRPMS/kernel-2.6.32-220.23.1.el6.src.rpm
wget http://kb.linuxvirtualserver.org/images/a/a5/Lvs-fullnat-synproxy.tar.gz
wget http://kb.linuxvirtualserver.org/images/b/b7/Linux-2.6.32-220.23.1.el6.x86_64.lvs.src.tar.gz
tar zxf Lvs-fullnat-synproxy.tar.gz
tar zxf Linux-2.6.32-220.23.1.el6.x86_64.lvs.src.tar.gzcat > ~/.rpmmacros << EOF
%_topdir /home/op/rpms
%_tmppath /home/op/rpms/tmp
%_sourcedir /home/op/rpms/SOURCES
%_specdir /home/op/rpms/SPECS
%_srcrpmdir /home/op/rpms/SRPMS
%_rpmdir /home/op/rpms/RPMS
%_builddir /home/op/rpms/BUILD
EOF
cd /home/op
mkdir rpms
mkdir rpms/tmp
mkdir rpms/SOURCES
mkdir rpms/SPECS
mkdir rpms/SRPMS
mkdir rpms/RPMS
mkdir rpms/BUILDrpm -ivh kernel-2.6.32-220.23.1.el6.src.rpm
cd /home/op/rpms/SOURCES
对于LVS,最好增加 HASH SIZE,否则请求量大的时候可能出现丢包情况(这是一个坑,后面的文章再说)。
vim config-generic 把 第一行的 # 改成 # x86_64,把 CONFIG_IP_VS_TAB_BITS=12 改成 CONFIG_IP_VS_TAB_BITS=20cd /home/op/rpms/SPECS
vim kernel.spec ,把 # % define buildid .local 修改为 %define buildid .ipvs_20bitcd /home/op/rpms/SPECS
rpmbuild -bp kernel.spec3). 增加patch
cd /home/op/rpms/BUILD/kernel-2.6.32-220.23.1.el6/linux-2.6.32-220.23.1.el6.ipvs_20bit.x86_64/
cp /home/op/lvs-fullnat-synproxy/lvs-2.6.32-220.23.1.el6.patch .
patch -p1 < ./lvs-2.6.32-220.23.1.el6.patch
cp configs/kernel-2.6.32-x86_64.config .config (默认的.config是DEBUG模式,开启的話很耗CPU,所以替换掉,这是一个坑。)改下内核子版本号。
vim Makefile
EXTRAVERSION = -220.23.1.e16make -j24
make modules_install;
make install修改内核启动参数
修改 /etc/grub.conf ,default=0,并在kernel一行中,添加“nohz=off ”(如果不关闭nohz,大压力下CPU0可能会消耗过高,压力不均匀),重启。
编译内核重启之后,开始安装LVS TOOLS(编译完内核先重启机器加载新的内核,否则下面模块无法安装)
cd /home/op/lvs-fullnat-synproxy
tar xzf lvs-tools.tar.gz
cd tools1). keepalived install
cd keepalived
./configure –with-kernel-dir=”/lib/modules/uname -r
/build”
make
make install2). ipvsadm install
cd ipvsadm;
make
make 这一步可能会遇到 ls: cannot access ../keepalived/keepalived/libipvs-2.6/libipvs.a: No such file ordirectory,这个错误,此时可以到 keepalived/keepalived/libipvs-2.6 目录去 make 一下。
make install3). quaage install
cd quagga;
./configure –disable-ripd –disable-ripngd –disable-bgpd –disable-watchquagga –disable-doc –enable-user=root –enable-vty-group=root –enable-group=root –enable-zebra –enable-ospfd –localstatedir=/var/run/quagga
make
make install
mkdir /var/run/quagga
因为我们用FULLNAT模式,所以在每台LVS机器上配置了28个local ip,对于一个请求LVS会选取一个IP和一个端口和后端机器(我们是NGINX)建立连接和转发数据,这样其实后端机器只能看到LVS的一个local ip了,对了让后端机器看到源请求IP,后端机器要装toa模块,和LVS一样要重编内核,来看看编译过程。
重复一下编译LVS内核的1) 和2) 步骤,然后:
1). 增加patch
cd /home/op/rpms/BUILD/
cd kernel-2.6.32-220.23.1.el6/linux-2.6.32-220.23.1.el6.ipvs_20bit.x86_64/
cp /home/op/lvs-fullnat-synproxy/toa-2.6.32-220.23.1.el6.patch ./
patch -p1cp configs/kernel-2.6.32-x86_64.config .config (默认的.config是DEBUG模式,开启的話很耗CPU,所以替换掉。) 2). 编译和安装
vim Makefile
EXTRAVERSION = -220.23.1.e16make -j24 (以M,即module方式编译)
make modules_install
make install3). 修改内核启动参数default=0,并在kernel一行中,添加“nohz=off ”(如果不关闭nohz,大压力下CPU0可能会消耗过高,压力不均匀)/etc/grub.conf,重启。
加载toa,把 modprobe toa 写在/etc/rc.d/rc.local