LVS+Keepalived+Nginx+Tomcat高可用负载均衡集群配置

一、负载均衡:必不可少的基础手段

LVS作用:实现负载均衡

Keepalived作用:监控集群系统中各个服务节点的状态,HA cluster。

配置LVS有两种方式:

1. 通过ipvsadm命令行方式配置

2. 通过Redhat提供的工具piranha来配置LVS

1.1 找更多的牛来拉车吧

  当前大多数的互联网系统都使用了服务器集群技术,集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是Web应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等等。

 

古人有云:当一头牛拉不动车的时候,不要去寻找一头更强壮的牛,而是用两头牛来拉车

load balance

  在实际应用中,在Web服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为Web服务器流量的入口,挑选最合适的一台Web服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。

1.2 负载均衡的类型

  负载均衡可以采用硬件设备(例如常常听见的F5),也可以采用软件负载。

  商用硬件负载设备成本通常较高(一台几十万上百万很正常),所以在条件允许的情况下我们会采用软件负载;

  软件负载解决的两个核心问题是:选谁、转发,其中最著名的是LVS(Linux Virtual Server)。

传送门->关于负载均衡的实现方式类型等介绍请浏览我的另一篇博文:《大型网站技术架构》读书笔记之六:永无止境之网站的伸缩性架构

二、初识LVS:Linux Virtual Server

2.1 LVS是神马东西

  LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目,它的官方站点是www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分,在Linux2.4内核以前,使用LVS时必须要重新编译内核以支持LVS功能模块,但是从Linux2.4内核以后,已经完全内置了LVS的各个功能模块,无需给内核打任何补丁,可以直接使用LVS提供的各种功能。

2.2 LVS有神马作用

  LVS主要用于服务器集群的负载均衡。它工作在网络层,可以实现高性能,高可用的服务器集群技术。它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。它易用,配置非常简单,且有多种负载均衡的方法。它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。

  LVS自从1998年开始,发展到现在已经是一个比较成熟的技术项目了。可以利用LVS技术实现高可伸缩的、高可用的网络服务,例如WWW服务、Cache服务、DNS服务、FTP服务、MAIL服务、视频/音频点播服务等等,有许多比较著名网站和组织都在使用LVS架设的集群系统,例如:Linux的门户网站(www.linux.com)、向RealPlayer提供音频视频服务而闻名的Real公司(www.real.com)、全球最大的开源网站(sourceforge.net)等。

2.3 LVS的体系结构

  使用LVS架设的服务器集群系统有三个部分组成:

  (1)最前端的负载均衡层,用Load Balancer表示;

  (2)中间的服务器集群层,用Server Array表示;

  (3)最底端的数据共享存储层,用Shared Storage表示;

  在用户看来,所有的内部应用都是透明的,用户只是在使用一个虚拟服务器提供的高性能服务。

传送门->关于体系结构的详细介绍,请浏览南飞蚂蚁的blog:http://ixdba.blog.51cto.com/2895551/552947

2.4 LVS负载均衡机制

  (1)LVS是四层负载均衡,也就是说建立在OSI模型的第四层——传输层之上,传输层上有我们熟悉的TCP/UDP,LVS支持TCP/UDP的负载均衡。因为LVS是四层负载均衡,因此它相对于其它高层负载均衡的解决办法,比如DNS域名轮流解析、应用层负载的调度、客户端的调度等,它的效率是非常高的。

  (2)LVS的转发主要通过修改IP地址(NAT模式,分为源地址修改SNAT和目标地址修改DNAT)、修改目标MAC(DR模式)来实现。

  ①NAT模式:网络地址转换

NAT

  NAT(Network Address Translation)是一种外网和内网地址映射的技术。NAT模式下,网络数据报的进出都要经过LVS的处理。LVS需要作为RS(真实服务器)的网关。当包到达LVS时,LVS做目标地址转换(DNAT),将目标IP改为RS的IP。RS接收到包以后,仿佛是客户端直接发给它的一样。RS处理完,返回响应时,源IP是RS IP,目标IP是客户端的IP。这时RS的包通过网关(LVS)中转,LVS会做源地址转换(SNAT),将包的源地址改为VIP,这样,这个包对客户端看起来就仿佛是LVS直接返回给它的。客户端无法感知到后端RS的存在。

  ②DR模式:直接路由

DR

  DR模式下需要LVS和RS集群绑定同一个VIP(RS通过将VIP绑定在loopback实现),但与NAT的不同点在于:请求由LVS接受,由真实提供服务的服务器(RealServer, RS)直接返回给用户,返回的时候不经过LVS。详细来看,一个请求过来时,LVS只需要将网络帧的MAC地址修改为某一台RS的MAC,该包就会被转发到相应的RS处理,注意此时的源IP和目标IP都没变,LVS只是做了一下移花接木。RS收到LVS转发来的包时,链路层发现MAC是自己的,到上面的网络层,发现IP也是自己的,于是这个包被合法地接受,RS感知不到前面有LVS的存在。而当RS返回响应时,只要直接向源IP(即用户的IP)返回即可,不再经过LVS。

  (3)DR负载均衡模式数据分发过程中不修改IP地址,只修改mac地址,由于实际处理请求的真实物理IP地址和数据请求目的IP地址一致,所以不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。因此,DR模式具有较好的性能,也是目前大型网站使用最广泛的一种负载均衡手段。

三、构建实战:LVS+Keepalived实现负载均衡

3.1 实验结构总览

  (1)本次基于VMware Workstation搭建一个四台Linux(CentOS 6.4)系统所构成的一个服务器集群,其中两台负载均衡服务器(一台为主机,另一台为备机),另外两台作为真实的Web服务器(向外部提供http服务,这里仅仅使用了CentOS默认自带的http服务,没有安装其他的类似Tomcat、Jexus服务)。

  (2)本次实验基于DR负载均衡模式,设置了一个VIP(Virtual IP)为192.168.80.200,用户只需要访问这个IP地址即可获得网页服务。其中,负载均衡主机为192.168.80.100,备机为192.168.80.101。Web服务器A为192.168.80.102,Web服务器B为192.168.80.103。

3.2 基础准备工作

  以下工作针对所有服务器,也就是说要在四台服务器中都要进行配置:

  (1)绑定静态IP地址

  命令模式下可以执行setup命令进入设置界面配置静态IP地址;x-window界面下可以右击网络图标配置;配置完成后执行service network restart重新启动网络服务;

  验证:执行命令ifconfig

  (2)设定主机名

  ①修改当前会话中的主机名,执行命令hostname xxxx (这里xxxx为你想要改为的名字)

  ②修改配置文件中的主机名,执行命令vi /etc/sysconfig/network (√一般需要进行此步凑才能永久更改主机名)

  验证:重启系统reboot

  (3)IP地址与主机名的绑定

  执行命令vi /etc/hosts,增加一行内容,如下(下面的从节点以你自己的为主,本实验搭建了两个从节点):

  192.168.80.100 lvs-master

  192.168.80.101 lvs-slave

  #下面是本次试验的两个真实服务器节点

  192.168.80.102 lvs-webserver1

  192.168.80.103 lvs-webserver2

  保存后退出

  验证:ping lvs-master

  (4)关闭防火墙

  ①执行关闭防火墙命令:service iptables stop

      验证:service iptables stauts

  ②执行关闭防火墙自动运行命令:chkconfig iptables off

  验证:chkconfig --list | grep iptables

3.3 配置两台Web服务器

  以下操作需要在角色为Web服务器的两台中进行,不需要在负载均衡服务器中进行操作:

  (1)开启http服务

  命令:service httpd start

  补充:chkconfig httpd on -->将httpd设为自启动服务

  (2)在宿主机访问Web网页,并通过FTP工具上传自定义网页:这里上传一个静态网页,并通过更改其中的html来区别两台Web服务器,以下图所示为例,其中一台显示from 192.168.80.102,而另一台显示from 192.168.80.103;

  (3)编辑realserver脚本文件

  ①进入指定文件夹:cd /etc/init.d/

  ②编辑脚本文件:vim realserver

复制代码

SNS_VIP=192.168.80.200
/etc/rc.d/init.d/functions
case "$1" in
start)
       ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP
       /sbin/route add -host $SNS_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 $SNS_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 Stoped"
       ;;
*)
       echo "Usage: $0 {start|stop}"
       exit 1
esac
exit 0

复制代码

  这里我们设置虚拟IP为:192.168.80.200

  ③保存脚本文件后更改该文件权限:chmod 755 realserver

  ④开启realserver服务:service realserver start

3.4 配置主负载服务器

  (1)安装Keepalived相关包

yum install -y keepalived

  在CentOS下,通过yum install命令可以很方便地安装软件包,但是前提是你的虚拟机要联网;

  (2)编辑keepalived.conf配置文件

  ①进入keepalived.conf所在目录:cd /etc/keepalived

  ②首先清除掉keepalived原有配置:> keepalived.conf

  ③重新编辑keepalived配置文件:vi keepalived.conf

复制代码

global_defs {  
   notification_email {  
         edisonchou@hotmail.com  
   }  
   notification_email_from sns-lvs@gmail.com  
   smtp_server 192.168.80.1  
   smtp_connection_timeout 30
   router_id LVS_DEVEL  # 设置lvs的id,在一个网络内应该是唯一的
}  
vrrp_instance VI_1 {  
    state MASTER   #指定Keepalived的角色,MASTER为主,BACKUP为备          
    interface eth1  #指定Keepalived的角色,MASTER为主,BACKUP为备
    virtual_router_id 51  #虚拟路由编号,主备要一致
    priority 100  #定义优先级,数字越大,优先级越高,主DR必须大于备用DR    
    advert_int 1  #检查间隔,默认为1s
    authentication {  
        auth_type PASS  
        auth_pass 1111  
    }  
    virtual_ipaddress {  
        192.168.80.200  #定义虚拟IP(VIP)为192.168.2.33,可多设,每行一个
    }  
}  
# 定义对外提供服务的LVS的VIP以及port
virtual_server 192.168.80.200 80 {  
    delay_loop 6 # 设置健康检查时间,单位是秒                    
    lb_algo wrr # 设置负载调度的算法为wlc                   
    lb_kind DR # 设置LVS实现负载的机制,有NAT、TUN、DR三个模式   
    nat_mask 255.255.255.0                
    persistence_timeout 0          
    protocol TCP                  
    real_server 192.168.80.102 80 {  # 指定real server1的IP地址
        weight 3   # 配置节点权值,数字越大权重越高              
        TCP_CHECK {  
        connect_timeout 10         
        nb_get_retry 3  
        delay_before_retry 3  
        connect_port 80  
        }  
    }  
    real_server 192.168.80.103 80 {  # 指定real server2的IP地址
        weight 3  # 配置节点权值,数字越大权重越高  
        TCP_CHECK {  
        connect_timeout 10  
        nb_get_retry 3  
        delay_before_retry 3  
        connect_port 80  
        }  
     }  
} 

复制代码

  (3)开启keepalived服务

service keepalived start

3.5 配置从负载服务器

  从负载服务器与主负载服务器大致相同,只是在keepalived的配置文件中需要改以下两处:

  (1)将state由MASTER改为BACKUP

  (2)将priority由100改为99

复制代码

vrrp_instance VI_1 {  
    state BACKUP # 这里改为BACKUP
    interface eth1  
    virtual_router_id 51  
    priority 99 # 这里改为99,master优先级是100
    advert_int 1  
    authentication {  
        auth_type PASS  
        auth_pass 1111  
    }  
    virtual_ipaddress {  
        192.168.80.200  
    }  
}  

复制代码

3.6 验证性测试

  (1)指定请求的均衡转发:因为两个Web服务器的权重都一样,所以会依次转发给两个Web服务器;

  (2)Web服务器发生故障时:

  ①A发生故障后,只从B获取服务;

  这里模拟192.168.80.102发生故障,暂停其http服务:service httpd stop

  再来看看这时从外部访问VIP时,便会只从192.168.80.103获取网页:

  ②A故障修复后,又从A获取服务;

  这里模拟192.168.80.102修复完成,重启其http服务:service httpd start

  再来看看这时从外部访问VIP,又可以从192.168.80.102获取网页:

  (3)主负载均衡服务器发生故障时,备机立即充当主机角色提供请求转发服务:

  这里模拟192.168.80.100发生故障,暂停其keepalived服务:service keepalived stop

  再来看看这时从外部访问VIP,还是可以正常获取网页:

学习小结

  LVS是目前广为采用的软件负载均衡解决方案,在一些大型企业级系统及互联网系统中应用。本次,简单地了解了一下LVS,并在Linux下搭建了一个小小的测试环境,借助Keepalived实现了一个最小化的负载均衡测试环境。LVS是一个可以工作在网络第四层的负载均衡软件,因此它相对于Nginx一类工作在第七层的负载均衡软件有着无可比拟的性能优势,而且它还是我国的章文嵩博士(现在阿里的副总裁,淘宝的技术专家)作为创始人发起的,现已经成为Linux内核的组成部分。

  当然,目前流行的LVS解决方案中,在Web服务器端也有采用了Nginx+Tomcat这样的搭配类型,静态文件和动态文件分开进行处理,也不失为一种有效的尝试。在以后的日子里,我还会尝试下在Linux下借助Jexus跑ASP.NET MVC项目,试试.NET项目在Linux下的运行效果,希望到时也可以做一些分享。好了,今天就到此停笔。

一.概述

LVS作用:实现负载均衡

Keepalived作用:监控集群系统中各个服务节点的状态,HA cluster。

配置LVS有两种方式:

1. 通过ipvsadm命令行方式配置

2. 通过Redhat提供的工具piranha来配置LVS

软件下载:

ipvsadm下载地址:

http://www.linuxvirtualserver.org/software/kernel-2.6/

Keepalived下载地址:

http://www.keepalived.org/software/

安装包版本:

ipvsadm-1.24.tar.gz

keepalived-1.2.2.tar.gz

操作系统版本:

Red Hat Enterprise Linux Server release 6.4 (Santiago)

二.服务器规划

服务器

IP地址

网关

虚拟设备名

虚拟IP(VIP)

部署应用

Master Director Server

10.50.13.34

10.50.13.1

eth0:0

10.50.13.11

LVS+keepalived

Backup Director Server

10.50.13.35

10.50.13.1

eth0:0

10.50.13.11

LVS+keepalived

Real server1

10.50.13.36

10.50.13.1

lo:0

10.50.13.11

Nginx+tomcat

Real server2

10.50.13.37

10.50.13.1

lo:0

10.50.13.11

Nginx+tomcat

三.LVS安装配置

1.通过ipvsadm软件配置LVS,在Director Serve上安装IPVS管理软件

通过如下命令检查kernel是否已经支持LVS的ipvs模块:

$ modprobe -l |grep ipvs
kernel/net/netfilter/ipvs/ip_vs.ko
kernel/net/netfilter/ipvs/ip_vs_rr.ko
kernel/net/netfilter/ipvs/ip_vs_wrr.ko
kernel/net/netfilter/ipvs/ip_vs_lc.ko
kernel/net/netfilter/ipvs/ip_vs_wlc.ko
kernel/net/netfilter/ipvs/ip_vs_lblc.ko
kernel/net/netfilter/ipvs/ip_vs_lblcr.ko
kernel/net/netfilter/ipvs/ip_vs_dh.ko
kernel/net/netfilter/ipvs/ip_vs_sh.ko
kernel/net/netfilter/ipvs/ip_vs_sed.ko
kernel/net/netfilter/ipvs/ip_vs_nq.ko
kernel/net/netfilter/ipvs/ip_vs_ftp.ko

如果有类似上面的输出,表明系统内核已经默认支持了IPVS模块。接着就可以安装IPVS管理软件了。

2. 安装ipvsadm

$ tar zxf ipvsadm-1.24.tar.gz
$ cd ipvsadm-1.24
$ sudo make
$ sudo make install

make时可能会遇到报错,由于编译程序找不到对应内核的原因,执行以下命令后继续编译

$ ln -s /usr/src/kernels/2.6.18-164.el5-x86_64/ /usr/src/linux

3. ipvsadm配置

为了管理和配置的方便,将ipvsadm配置写成启停脚本:

$ cat lvsdr 
#!/bin/bash
# description: Start LVS of Director server
VIP=10.50.13.11
RIP=`echo 10.50.13.{36..37}`
. /etc/rc.d/init.d/functions
case "$1" in
start)
echo " start LVS of Director Server"
# set the Virtual IP Address and sysctl parameter
/sbin/ifconfig eth0:0 ${VIP} broadcast ${VIP} netmask 255.255.255.255 up
/sbin/route add -host ${VIP} dev eth0:0
#echo "1" >/proc/sys/net/ipv4/ip_forward
#Clear IPVS table
/sbin/ipvsadm -C
#set LVS
/sbin/ipvsadm -A -t ${VIP}:80 -s rr -p 600
/sbin/ipvsadm -A -t ${VIP}:90 -s rr -p 600
for rip in ${RIP};do
/sbin/ipvsadm -a -t ${VIP}:80 -r ${rip}:80 -g
/sbin/ipvsadm -a -t ${VIP}:90 -r ${rip}:90 -g
done
#Run LVS
/sbin/ipvsadm
;;
stop)
echo "close LVS Directorserver"
#echo "0" >/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -C
/sbin/ifconfig eth0:0 down
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac

然后把文件放到/etc/init.d下,执行:

$ chomd +x /etc/init.d/lvsdr

$ service lvsdr start

4. Real server 配置

在lvs的DR和TUN模式下,用户的访问请求到达真实服务器后,是直接返回给用户的,而不再经过前端的Director Server,因此,就需要在每个Real server节点上增加虚拟的VIP地址,这样数据才能直接返回给用户,增加VIP地址的操作可以通过创建脚本的方式来实现,创建文件/etc /init.d/lvsrs,脚本内容如下:

$ cat /etc/init.d/lvsrs 
#!/bin/bash
VIP=10.50.13.11
/sbin/ifconfig lo:0 ${VIP} broadcast ${VIP} netmask 255.255.255.255 up
/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

四.Keepalived安装配置

以下是通过具有sudo权限的普通用户安装的。

tar zxf keepalived-1.2.2.tar.gz
cd keepalived-1.2.2
./configure --sysconf=/etc --with-kernel-dir=/usr/src/kernels/2.6.32-358.el6.x86_64
sudo make
sudo make install
sudo cp /usr/local/sbin/keepalived /sbin/keepalived

配置keepalived

Keepavlived的配置文件在/etc/keepalived/目录下,编辑后的keepavlived的MASTER配置文件如下:

$ cat /etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
      notification_email {
      Eivll0m@xxx.com
      }
      notification_email_from keepalived@localhost
      smtp_server 10.50.13.34
      smtp_connect_timeout 30
      router_id LVS_MASTER
}

vrrp_instance VI_1 {
  state MASTER
  interface eth0
  virtual_router_id 51
  priority 100
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass 1111
  }
  virtual_ipaddress {
    10.50.13.11
  }
  notify_master "/etc/init.d/lvsdr start"
  notify_backup "/etc/init.d/lvsdr stop"
}

virtual_server 10.50.13.11 80 {
  delay_loop 2
  lb_algo rr
  lb_kind DR
  #nat_mask 255.255.255.0
  persistence_timeout 50
  protocol TCP

  real_server 10.50.13.36 80 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
    }
  }
  real_server 10.50.13.37 80 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
        }
  }

virtual_server 10.50.13.11 90 {
  delay_loop 2
  lb_algo rr
  lb_kind DR
  #nat_mask 255.255.255.0
  persistence_timeout 50
  protocol TCP

  real_server 10.50.13.36 90 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
    }
  }
  real_server 10.50.13.37 90 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
    }
  }
}

BACKUP配置文件如下:

$ cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {

  notification_email {
  Eivll0m@xxx.com
  }
  notification_email_from keepalived@localhost
  smtp_server 10.50.13.35 
  smtp_connect_timeout 30
  router_id LVS_BACKUP
}

vrrp_instance VI_1 {
  state BACKUP
  interface eth0
  virtual_router_id 51
  priority 90
  advert_int 1
  authentication {
  auth_type PASS
  auth_pass 1111
      }
virtual_ipaddress {
  10.50.13.11
  }
  notify_master "/etc/init.d/lvsdr start"
  notify_backup "/etc/init.d/lvsdr stop"
}

virtual_server 10.50.13.11 80 {
  delay_loop 2
  lb_algo rr
  lb_kind DR
  #nat_mask 255.255.255.0
  persistence_timeout 50
  protocol TCP

  real_server 10.50.13.36 80 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
  }
}
real_server 10.50.13.37 80 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
  }
}

virtual_server 10.50.13.11 90 {
  delay_loop 2
  lb_algo rr
  lb_kind DR
  #nat_mask 255.255.255.0
  persistence_timeout 50
  protocol TCP

  real_server 10.50.13.36 90 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
  }

}
  real_server 10.50.13.37 90 {
  weight 1
  TCP_CHECK {
    connect_timeout 3
    nb_get_retry 3
    delay_before_retry 3
  }
  }
}

keepalived启动方法:

/etc/init.d/keepalived start

五.nginx、tomcat安装配置

1.安装nginx

$ tar zxf nginx-1.6.1.tar.gz
$ cd nginx-1.6.1
$ ./configure --prefix=/app/nginx --with-http_ssl_module --with-http_realip_module --add-module=/app/soft/nginx-sticky
$ make
$ make install

2.nginx配置:

upstream test_80 {
  sticky;
  server 10.50.13.36:8080;
  server 10.50.13.37:8080;
}
upstream test_90 {
  sticky;
  server 10.50.13.36:8090;
  server 10.50.13.37:8090;
}

server {
      listen 80;
  server_name localhost;
  .....
  location ^~ /test/ {
  proxy_pass http://test_80;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

server {
      listen 90;
  server_name localhost;
  .....
  location ^~ /test/ {
  proxy_pass http://test_80;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

3.安装tomcat(简单,过程略)

10.50.13.36/37每台机器各安装两个tomcat,端口分别启用8080和8090

安装路径:/app/tomcat、/app/tomcat2

4.给tomcat准备测试文件

10.50.13.36:

$ mkdir /app/tomcat/webapps/test
$ cd /app/tomcat/webapps/test
$ vi index.jsp #添加如下内容

<%@ page language="java" %>
<html>
  <head><title>10.50.13.36_tomcat1</title></head>
  <body>
    <h1><font color="blue">10.50.13.36_tomcat1 </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
      </tr>
    </table>
  </body>
</html>

 

$ mkdir /app/tomcat/webapps/test
$ cd /app/tomcat/webapps/test
$ vi index.jsp #添加如下内容

 

<%@ page language="java" %>
<html>
  <head><title>10.50.13.36_tomcat2</title></head>
  <body>
    <h1><font color="blue">10.50.13.36_tomcat2 </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
      </tr>
    </table>
  </body>
</html>

 

10.50.13.37:

$ mkdir /app/tomcat/webapps/test
$ cd /app/tomcat/webapps/test
$ vi index.jsp #添加如下内容

<%@ page language="java" %>
<html>
  <head><title>10.50.13.37_tomcat1</title></head>
  <body>
    <h1><font color="blue">10.50.13.37_tomcat1 </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
      </tr>
    </table>
  </body>
</html>

 

$ mkdir /app/tomcat/webapps/test
$ cd /app/tomcat/webapps/test
$ vi index.jsp #添加如下内容

 

<%@ page language="java" %>
<html>
  <head><title>10.50.13.37_tomcat2</title></head>
  <body>
    <h1><font color="blue">10.50.13.37_tomcat7 </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
      </tr>
    </table>
  </body>
</html>

六.测试

通过浏览器访问http://10.50.13.11/test/index.jsp

 

查看LVS统计信息:

通过curl访问http://10.50.13.11/test/index.jsp

查看LVS统计信息:

通过浏览器访问http://10.50.13.11:90/test/index.jsp

 

查看LVS统计信息:可以看到10.50.13.11:dnsix有变化了。

keepalived测试,停掉master上的keepalived服务,看看VIP是否会漂移到BACKUP上面

通过以上测试发现,BACKUP已正常接管服务了。

参考资料

(1)王晨纯,《Web基础架构:负载均衡和LVS》:http://www.importnew.com/11229.html

(2)win_xp,《LVS简介及使用》:http://www.cnblogs.com/codebean/archive/2011/07/25/2116043.html

(3)jiwang1980,《LVS+Keepalived》:http://7567567.blog.51cto.com/706378/578289

(4)南飞蚂蚁的BLOG,《Linux负载均衡软件LVS之概念篇》:http://ixdba.blog.51cto.com/2895551/552947

(5)AKing王国,《四层和七层负载均衡的区别》:http://kb.cnblogs.com/page/188170/

 

一、网站架构的伸缩性设计

1.1 不同功能进行物理分离实现伸缩

  (1)纵向分离:将业务处理流程上得不同部分分离部署,实现系统的伸缩性;

  (2)横向分离:将不同的业务模块分离部署,实现系统的伸缩性;

1.2 单一功通过集群规模实现伸缩

  使用服务器集群,即将相同服务部署在多台服务器上构成一个集群整体对外提供服务。具体来说,集群伸缩性又分为应用服务器集群伸缩性和数据服务器集群伸缩性。这两种集群对于数据状态管理的不同,技术实现也有很大的区别。

 It is said that 当一头牛拉不动车的时候,不要去寻找一头更强壮的牛,而是用两头牛来拉车

二、应用服务器集群的伸缩性设计

2.1 应用服务器那点必须知道的事儿

  (1)应用服务器应该被设计成无状态的,即应用服务器不存储请求上下文信息;构建集群后,每次用户的请求都可以发到集群中任意一台服务器上处理,任何一台服务器的处理结果都是相同的;

  (2)HTTP本身是一个无状态的连接协议,为了支持客户端与服务器之间的交互,我们就需要通过不同的技术为交互存储状态,而这些不同的技术就是Cookie和Session了。

  (3)HTTP请求的分发是应用服务器集群实现伸缩性的核心问题,而负载均衡服务器就是HTTP请求的分发装置,它是网站必不可少的基础手段,也被称为网站的杀手锏之一。

2.2 负载均衡技术—网站必不可少的基础技术手段

  负载均衡的实现方式多种多样,从硬件到软件,从商业产品到开源产品,应有尽有。但是,实现负载均衡的基础技术不外乎以下几种:

  (1)HTTP重定向负载均衡  评价:★★

  此方案的优点是简单易行,缺点是:

  ①浏览器需要两次请求才能完成一次访问,性能较差

  ②重定向服务器自身的处理能力有可能成为瓶颈,整个集群的伸缩性规模有限

  ③使用HTTP 302重定向有可能使搜索引擎判断为SEO作弊,降低搜索排名;

  (2)DNS域名解析负载均衡  评价:★★★

  此方案要求在DNS服务器中配置多个A记录,例如:

www.mysite.com IN A 114.100.80.1
www.mysite.com IN A 114.100.80.2
www.mysite.com IN A 114.100.80.3

  此方案的优点是将负载均衡的工作转交给了DNS,省掉了网站管理维护负载均衡服务器的麻烦。而缺点是:

  ①目前的DNS是多级解析,每一级DNS都可能缓存A记录,当某台服务器下线后,即使修改了DNS的A记录,要使其生效仍然需要较长时间。这段期间,会导致用户访问已经下线的服务器造成访问失败。

  ②DNS负载均衡的控制权在域名服务商那里,网站无法对其做更多改善和管理;

TIPS:事实上,大型网站总是部分使用DNS域名解析,利用域名解析作为第一级负载均很手段,即域名解析得到的一组服务器不是实际的Web服务器,而是同样提供负载均衡的内部服务器,这组内部服务器再进行负载均衡,请求分发到真实的Web服务器上。

  (3)反向代理负载均衡  评价:★★★★

  Web服务器不需要使用外部IP地址,而反向代理服务器则需要配置双网卡和内外部两套IP地址。

  此方案的优点是和反向代理服务器功能集成在一起,部署简单。缺点是反向代理服务器是所有请求和响应的中转站,其性能可能会成为瓶颈

  (4)IP负载均衡  评价:★★★★

  此方案优点在于在内核进程完成数据分发,较反向代理负载均衡(在应用程序中分发数据)有更好的处理性能。缺点是由于所有请求响应都需要经过负载均衡服务器,集群的最大响应数据吞吐量不得不受制于负载均衡服务器网卡带宽

  (5)数据链路层负载均衡  评价:★★★★★

  此种方式又称作三角传输模式,负载均衡数据分发过程中不修改IP地址,只修改mac地址,由于实际处理请求的真实物理IP地址和数据请求目的IP地址一致,所以不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。这种负载均衡方式又称作直接路由方式(DR)

  使用三角传输模式的链路层负载均衡是目前大型网站使用最广泛的一种负载均衡手段。在Linux平台上最好的链路层负载均衡开源产品是LVS(Linux Virutal Server)。

2.3 负载均衡算法—负载均衡技术赖以生存的核心

  前面的方法解决了负载均衡通过何种方式实现,而更为重要的则是如何从Web服务器列表中计算得到一台Web服务器的地址,而这正是负载均衡的核心—算法。这里简单介绍一下通常的集中负载均衡计算的算法,如果需要深入了解请自行百度。

  (1)轮询

  所有请求被以此分发到每台应用服务器上,即每台服务器需要处理的请求数目都相同,适合于所有服务器硬件都相同的场景。

  (2)加权轮询

  根据应用服务器的配置性能的情况,在轮询的基础上,按照配置的权重将请求分发到每个服务器,高性能的服务器能分配更多的请求。

  (3)随机

  此算法比较简单实用,请求被随机分配到各个应用服务器,因为好的随机数本身就很均衡。

  (4)最少连接

  记录每个应用服务器正在处理的连接数(请求数),将新到的请求分发到最少连接的服务器上,应该说,这是最符合负载均衡定义的算法。

  (5)源地址散列

  根据请求来源的IP地址进行Hash计算得到应用服务器,这样来自同一个IP地址的请求总在同一个服务器上处理,该请求的上下文信息可以存储在这台服务器上,在一个会话周期内重复使用,从而实现会话粘滞。

三、分布式缓存集群的伸缩性设计

  不同于应用服务器集群的伸缩性设计,分布式缓存集群的伸缩性不能使用简单的负载均衡手段来实现。因为:分布式缓存服务器集群中缓存的数据各不相同,缓存访问请求不可以在缓存服务器集群中的任意一台处理,必须先找到缓存有需要的数据的服务器,然后才能访问

  分布式缓存集群伸缩性设计的目标:让新上线的缓存服务器对整个分布式缓存集群影响最小,也就是说新加入缓存服务器后应使整个缓存服务器集群中已经缓存的数据尽可能还被访问到。

  (1)以Memcached为代表的分布式缓存集群的访问模型

  以上图片展示了一个典型的缓存写操作,应用程序需要写缓存数据<'CHENGDU',DATA>,API将KEY('CHENGDU')输入路由算法模块,路由算法根据KEY和Memcached服务器集群列表计算得到一台服务器编号(如Node1),进而得到该机器的IP地址和端口(10.0.0.1:91000)。然后,API调用通信模块和编号为Node1的Memcached服务器进行通信,将数据<'CHENGDU',DATA>写入该服务器,至此便完成了一次分布式缓存的写操作。

  而读操作和写操作一样,使用同样的路由算法和服务器列表,只要提供相同的KEY(如上面提到的'CHENGDU'),Memcached客户端总是访问相通的服务器(如上面计算得到的Node1)去读取数据。

  (2)以Memcached为代表的分布式缓存集群的伸缩性挑战

  简单的路由算法(通过使用余数Hash)无法满足业务发展时服务器扩容的需要:缓存命中率下降。例如:当3台服务器扩容至4台时,采用普通的余数Hash算法会导致大约75%(3/4)被缓存了的数据无法正确命中,随着服务器集群规模的增大,这个比例会线性地上升。那么,可以想象,当100台服务器的急群众加入一台服务器,不能命中的概率大概是99%(N/N+1),这个结果显然是无法接受的。

  那么,能否通过改进路由算法,使得新加入的服务器不影响大部分缓存数据的正确性呢?请看下面的一致性Hash算法。

  (3)分布式缓存的一致性Hash算法

说明:一致性Hash算法是分布式缓存的核心理论,这里只是简单介绍一下,后续有空我会单独写一篇文章来详细介绍一致性Hash算法,以及用C#实现一致性Hash算法。

  一致性Hash算法通过一个叫做一致性Hash还的数据结构实现KEY到缓存服务器的Hash映射,如下图所示:

一致性Hash

  具体算法过程是:

  ①先构造一个长度为0~2^32(2的32次幂)个的整数环(又称:一致性Hash环),根据节点名称的Hash值将缓存服务器节点防置在这个Hash环中,如上图中的node1,node2等;

  ②根据需要缓存的数据的KEY值计算得到其Hash值,如上图中右半部分的“键”,计算其Hash值后离node2很近;

  ③在Hash环上顺时针查找距离这个KEY的Hash值最近的缓存服务器节点,完成KEY到服务器的Hash映射查找,如上图中离右边这个键的Hash值最近的顺时针方向的服务器节点是node2,因此这个KEY会到node2中读取数据;

  当缓存服务器集群需要扩容的时候,只需要将新加入的节点名称(如node5)的Hash值放入一致性Hash环中,由于KEY总是顺时针查找距离其最近的节点,因此新加入的节点只影响整个环中的一部分。如下图中所示,添加node5后,只影响右边逆时针方向的三个Key/Value对数据,只占整个Hash环中的一小部分。

node5

  因此,我们可以与之前的普通余数Hash作对比:采用一直性Hash算法时,当3台服务器扩容到4台时,可以继续命中原有缓存数据的概率为75%,远高于普通余数Hash的25%,而且随着集群规模越大,继续命中原有缓存数据的概率也会随之增大。当100台服务器增加1台时,继续命中的概率是99%。虽然,仍有小部分数据缓存在服务器中无法被读取到,但是这个比例足够小,通过访问数据库也不会对数据库造成致命的负载压力

四、数据存储服务器集群的伸缩性设计

  首先,数据存储服务器必须保证数据的可靠存储,任何情况下都必须保证数据的可用性和正确性。因此,缓存服务器集群的伸缩性架构方案不能直接适用于数据库等存储服务器。

  (1)关系数据库集群的伸缩性设计

  ①市场上主要的关系数据库都支持数据复制功能,使用这个功能可以对数据库进行简单伸缩。下图显示了使用数据复制的MySQL集群伸缩性方案:多台MySQL的角色有主从之分,写操作都在主服务器上,由主服务器将数据同步到集群中其他从服务器。而读操作及数据分析等离线操作都会在从服务器上完成。

  ②前面提到的业务分割模式也可以用在数据库,不同业务数据表部署在不同的数据库集群上,这就是所谓的“数据分库”;但是其有一个制约条件:跨库的表无法进行Join操作;

分库

  ③在实际运维中,对一些单表数据仍然很大的表,例如Facebook的用户数据库、淘宝的商品数据库等,还需要进行分片,将一张表拆分开分别存储在多个数据库中,这就是所谓的“数据分片”;

分表

  (2)NoSQL数据库的伸缩性设计

  首先,NoSQL主要指非关系的、分布式的数据库设计模式。也有许多专家将NoSQL解读为Not Only SQL,表示NoSQL是关系数据库的补充,而不是替代方案。一般而言,NoSQL数据库产品都放弃了关系数据库的两大重要基础:①以关系代数为基础的结构化查询语言(SQL)②事务的一致性保证(ACID);与之对应的是强化一些大型网站更关注的特性:高可用性和可伸缩性

  开源社区的NoSQL产品不尽其数,其支持的数据结构和伸缩性特性也各不相同。目前看来,应用最广泛的是Apache HBase。HBase的伸缩性主要依赖于其可分裂的HRegion可伸缩的分布式文件系统HDFS(如果您不知道HDFS又对HDFS有兴趣,可以阅读我的另一篇博文《不怕故障的海量存储—HDFS基础入门》)实现。

  上图是HBase的整体架构图:

  ①HBase中数据以HRegion为单位进行管理,也就是说应用程序如果想要访问一个数据,必须先找到HRegion,然后将数据读写操作提交给HRegion,由HRegion完成存储层面的数据操作。

  ②每个HRegion中存储一段Key区间(例如:[Key1,Key2))的数据,HRegionServer是物理服务器,每个HRegionServer上可以启动多个HRegion实例。当一个HRegion中写入的数据太多,达到配置的阀值时,HRegion会分裂成两个HRegion,并将HRegion在整个集群中进行迁移,以使HRegionServer的负载均衡。

  ③所有的HRegion的信息都(例如:存储的Key值区间、所在HRegionServer的IP地址和端口号等)记录在HMaster服务器上。同时为了保证高可用,HBase启动了多个HMaster,并通过ZooKeeper(一个支持分布式一致性的数据管理服务)选举出一个主服务器,通过这个主HMaster服务器获得Key值所在的HRegionServer,最后请求该HRegionServer上的HRegion实例,获得需要的数据。其具体的数据寻址访问流程如下图所示:

五、学习小结

  在本章的学习中,我们了解到要实现网站的可伸缩性,关键技术就在于如何构建“良好”的服务器集群。要达到良好的目标,就要求每次扩容和减少服务器时,对整个网站的影响是最小的,甚至无影响的。伸缩性是复杂的,没有通用的、完美的解决方案和产品。一个具有良好伸缩性的网站,其设计总是走在业务发展的前面,在业务需要处理更多访问和处理之前,就已经做好了充分的准备,当业务需要时,只需要增加服务器并简单部署就可以了,技术团队便可轻松应对了。

  在本篇的介绍中,有些核心的内容比如一致性Hash算法只是进行了简单的介绍,并没有深入的分析,这个源于我目前对其的理解还只是皮毛。等待我深入学习之后,我会抽空写一篇单独介绍一致性Hash算法的博文,并使用C#进行一个粗略的实现,有兴趣的朋友敬请期待吧。

  另外,前面几篇博文中有些园友提出介绍一些实践性质的东西,我在这里表示抱歉,因为本书只是单纯地讲解理论,而且也没有深入地去讲解这些理论,只是单纯地扩展知识面,管中窥豹,一览大型网站的技术体系。而我本人也还是一个即将求职和毕业的学生,在理论和实践上都缺乏相应的经验,但我会在精读完本书后去做一些相应场景的具体实践,比如使用Memcached或Redis构建分布式缓存集群,使用Mono在Linux下搭建ASP.NET MVC应用环境,使用高性能的Nginx或Jexus服务器构建反向代理负载均衡服务器环境,使用发布订阅模式实现MS SQL的读写分离实践等等,如果园友有兴趣的话,也可以自行找资料去做相关实践。如果觉得喜欢我的博文,那我只能说敬请期待了(现在时间宝贵啊,马上要找工作了,还得复习复习,再过段时间毕业论文的鸭梨又要来了,我勒个去),么么嗒。

参考文献

  (1)李智慧,《大型网站技术架构-核心原理与案例分析》,http://item.jd.com/11322972.html

  (2)老徐的私房菜,《HTTP无状态协议和Session原理》,http://laoxu.blog.51cto.com/4120547/1219699

  (3)百度百科,《一致性Hash算法》,http://baike.baidu.com/view/1588037.htm

  (4)charlee,《Memcached完全剖析》,http://kb.cnblogs.com/page/42731/

  (5)bluishglc,《数据库Sharding的基本思想和切分策略》,http://blog.csdn.net/bluishglc/article/details/6161475

本章思维导图

 

作者:周旭龙

出处:http://www.cnblogs.com/edisonchou/

展开阅读全文

没有更多推荐了,返回首页