Nginx+tomcat+session复制负载均衡群集


一.Nginx应用

        通常情况下,一台tomcat站点由于可能出现单点故障及无法应付过多客户复杂多样的请求等问题,不能单独应用于生产环境,所以我们需要一套更可靠的解学方案来完善Web站点架构

        

Nginx是一款非常优秀的http服务器软件

        支持高达50000个并发连接数的响应

        拥有强大的静态资源处理能力

        运行稳定 

        内存、CPU等系统资源消耗非常低


目前很多大型网站都应用Nginx服务器作为后端网站程序的反向代理及负载均衡器,提升整个站点的负载并发能力



二.Nginx负载均衡实现原理


Nginx实现负载均衡是通过反向代理来实现的

spacer.gifspacer.gifspacer.gifspacer.gif

Nginx配置反向代理的主要参数

      

       upstream服务池名

       配置后端服务器池,以提供相应数据


       proxy_pass   http://服务器池名

       配置将访问请求转发给后端服务器池的服务器处理



三.Session概述

    应用服务器的高可用负载均衡架构设计主要服务于服务无状态这一特性(静态页面),但是事实上,绝大多数业务总是有状态的,例如:交易类的电子商务网站,需要有购物车记录用户的购买信息,用于每次购买请求都是向购物车中增加新的商品;社交网站中,需要记录用户当前的登录状态,获取用户的个人信息、最新发布的消息及好友请求状态等,用户每次刷新页面都需要更新这些信息。

 

WEB应用中将这些多次请求修改使用的上下文对象称作会话(Session),单机情况下,Session可由部署在服务器上的WEB容器(TomcatResin)进行管理。但在使用高可用负载均衡的集群环境中,由于负载均衡服务器可能会将每次请求分发到集群任何一台应用服务器(Tomcat)上,所以保证每次请求依然能够获得正确的Session比在单机上实现要复杂的多。

 

Session复制

Session复制是小型企业应用使用较多的一种服务器集群Session管理机制。应用服务器开启Web容器的Session复制功能,在集群中的几台服务器之间同步Session对象,使每台服务器上都保存了所有用户的Session信息,这样任何一台机器宕机都不会导致Session数据的丢失,而服务器使用Session时,也只需要在本机获取即可。

 

 这种方案实现简单,从本机读取Session信息也很快速,但只能应用在集群规模比较小的环境下。当集群规模较大时,集群服务器间需要大量的通信进行Session复制,占用服务器和网络的大量资源,系统不堪负担。而且由于所有用户的Session信息在每台服务器上都有备份,在大量用户访问的情况下,甚至会出现服务器内存不够Session使用的情况。

   

    而大型网站的核心应用集群就是数千台服务器,同时在线用户可达千万,因此并不适用这种方案。



三.Nginx+Tomcat+session复制负载均衡案例


本案例以Nginx作为负载均衡器,Tomcat作为应用服务器

环境描述:

操作系统

IP地址

主机名

软件包列表

CentOS6.6-x86_64

192.168.8.10

nginx

nginx

CentOS6.6-x86_64

192.168.8.20

Node1

JDK Tomcat 

CentOS6.6-x86_64

192.168.8.30

Node2

JDK Tomcat


配置过程:

安装前准备配置:

配置所有机器:

[root@localhost ~]# cat /etc/hosts

192.168.8.10 nginx

192.168.8.20 node1

192.168.8.30 node2

[root@localhost ~]# service iptables stop

[root@localhost ~]# setenforce 0


1)Nginx 服务器配置:

Nginx配置负载均衡

        在Nginx服务上安装Nginx,反向代理两个Tomcat站点,并实现负载均衡

        关闭iptables防火墙

        安装Nginx依赖软件包

        解压并编译安装Nginx

        配置nginx.conf,添加upstream配置段与proxy_pass

        检测配置文件与启动Nginx

        测试负载均衡效果


配置主机名:

[root@localhost ~]# hostname nginx

[root@localhost ~]# bash



安装nginx软件包并修改:

[root@nginx ~]# yum -y install pcre-devel zlib-devel openssl-devel

[root@nginx ~]# tar xf nginx-1.6.2.tar.gz -C /usr/src/

[root@nginx ~]# useradd -M -s /sbin/nologin nginx

[root@nginx ~]# cd /usr/src/nginx-1.6.2/


[root@nginx nginx-1.6.2]#  ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-file-aio --with-http_stub_status_module --with-http_ssl_module --with-http_flv_module --with-http_gzip_static_module && make && make install


[root@nginx nginx-1.6.2]# vim /usr/local/nginx/conf/nginx.conf

添加红色边框里的内容

upstream tomcat_server {

        server 192.168.8.20:8080 weight=1;

        server 192.168.8.30:8080 weight=1;

    }

proxy_pass http://tomcat_server; 注意此段添加位置在Nginx根目录的location段落中

spacer.gifwKiom1e-iODCeMU1AABTZQ7CR8I950.png-wh_50

[root@nginx nginx-1.6.2]# /usr/local/nginx/sbin/nginx -t

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

[root@nginx nginx-1.6.2]# /usr/local/nginx/sbin/nginx



2)安装配置Tomcat1 && Tomcat2

安装JDK方法:

软件包格式

描述

jdk-*.tar.gz

源代码包,解压后配置环境变量

jdk-*.bin

通用二进制,给执行权限,执行后配置环境变量

jdk-*.rpm        

  1. 直接安装rpm软件包

  2. 先安装rpm软件包,生成.bin格式的(通用二进制)

jdk-*.exe

Windows平台使用,直接安装使用


第一台Tomcat服务器

[root@localhost ~]# hostname node1  另外一台机器配置为node2

[root@localhost ~]# bash


[root@node1 ~]# service iptables stop


卸载RPM格式的JDK


[root@node1 ~]# rpm -qa | grep java

tzdata-java-2013g-1.el6.noarch

java-1.6.0-openjdk-devel-1.6.0.0-1.66.1.13.0.el6.x86_64

java-1.7.0-openjdk-devel-1.7.0.45-2.4.3.3.el6.x86_64

java-1.6.0-openjdk-1.6.0.0-1.66.1.13.0.el6.x86_64

java-1.7.0-openjdk-1.7.0.45-2.4.3.3.el6.x86_64

[root@node1 ~]# rpm -e java-1.6.0-openjdk-devel

[root@node1 ~]# rpm -e java-1.7.0-openjdk-devel

[root@node1 ~]# rpm -e java-1.7.0-openjdk

[root@node1 ~]# rpm -e java-1.6.0-openjdk


解压后会生成jdk1.7.0_65文件夹,将文件夹移动到/usr/local下并重命名为java

[root@node1 ~]# tar xf jdk-7u65-linux-x64.gz

[root@node1 ~]# mv jdk1.7.0_65/ /usr/local/java

[root@node1 ~]# vim /etc/profile

export JAVA_HOME=/usr/local/java    #设置java根目录

export PATH=$PATH:$JAVA_HOME/bin    #在PATH环境变量中添加java跟目录的bin子目录

spacer.gifwKiom1e-iTjBuNgcAAAQ2ER2J4M501.png-wh_50


执行脚本加载环境变量,使其生效


[root@node1 ~]# source /etc/profile

运行 java -version 或者 javac -version 命令查看java版本


[root@node1 ~]# java -version

java version "1.7.0_65"

Java(TM) SE Runtime Environment (build 1.7.0_65-b17)

Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

[root@node1 ~]# tar xf apache-tomcat-7.0.54.tar.gz 


解压后生成apache-tomcat-7.0.54文件夹,将该文件夹移动到/usr/local下,并改名为tomcat

[root@node1 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7


启动Tomcat


[root@node1 ~]# /usr/local/tomcat7/bin/startup.sh 

Using CATALINA_BASE:   /usr/local/tomcat7

Using CATALINA_HOME:   /usr/local/tomcat7

Using CATALINA_TMPDIR: /usr/local/tomcat7/temp

Using JRE_HOME:        /usr/local/java

Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar

Tomcat started.


Tomcat 默认运行在8080端口


[root@node1 ~]# netstat -anupt | grep :8080

tcp        0      0 :::8080                     :::*                        LISTEN      1358/java           

浏览器访问测试 http://192.168.8.20:8080

spacer.gifwKiom1e-iXjww0jlAAHrUvqMwLI570.png-wh_50



Session复制:

    Tomcat支持Session集群,可在各Tomcat服务器间复制全部session信息,当后端一台Tomcat服务器宕机后,Nginx重新调度用户请求分配到另外一台服务器,从另一台Tomcat服务上获取用户的session信息。

Session集群可在Tomcat服务器规模(一般10台以下)不大时使用,否则会导致复制代价过高


修改Tomcat配置文件

tomcat的网页存放路径为/usr/local/tomcat7/webapps/ROOT下


[root@node1 webapps]# vim /usr/local/tomcat7/conf/server.xml

 去掉注释110行的注释让其生效

wKiom1e-iaXD7EJeAAAQrbKIUm4728.png-wh_50

注:如果取消此行注释后发生tomcat不能启动,或启动后自动关闭等,原因可能是没有添加组播地址,需要手动添加组播地址,命令格式:    spacer.gif

route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

[root@node1 webapps]# vim /usr/local/tomcat7/webapps/ROOT/WEB-INF/web.xml 

spacer.gifwKioL1e-ib_gDG3jAAANwHXtddw084.png-wh_50


建立session.jsp测试页面

[root@node1 ~]# vim /usr/local/tomcat/webapps/session.jsp

Session ID:<%= session.getId() %><BR>

SessionPort:<%= request.getServerPort() %>

<% out.println("This tomcat server 192.168.8.20");%>


另一台机器的IP修改为192.168.8.30

Session ID:<%= session.getId() %><BR>

SessionPort:<%= request.getServerPort() %>

<% out.println("This tomcat server 192.168.8.30");%>


重行启动tomcat


[root@node1 webapps]# /usr/local/tomcat7/bin/shutdown.sh && /usr/local/tomcat7/bin/startup.sh

Using CATALINA_BASE:   /usr/local/tomcat

Using CATALINA_HOME:   /usr/local/tomcat

Using CATALINA_TMPDIR: /usr/local/tomcat/temp

Using JRE_HOME:        /usr/local/java

Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

 

Using CATALINA_BASE:   /usr/local/tomcat

Using CATALINA_HOME:   /usr/local/tomcat

Using CATALINA_TMPDIR: /usr/local/tomcat/temp

Using JRE_HOME:        /usr/local/java

Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

Tomcat started.



第二台tomcat配置同上


Session测试:

浏览器访问测试http://192.168.8.10/session.jsp刷新后session ID未发生变化

spacer.gifwKioL1e-jyTAglL5AABgdF51gZY809.png

spacer.gif

wKiom1e-jzChmShrAABiCaWbyA4486.png


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

Nginx负载均衡常用算法与配置方法

        在多个应用程序间提供负载均衡是一种常用的提高资源利用率的技术,提高服务器的吞吐量,减少延迟,确保应用程序容错。Nginx可以做为一个高效的http负载均衡器来将负载分发到多个应用程序上以提高性能,它也是一种可靠地,可伸缩的web应用程序服务器。


nginx 负载均衡的算法


轮询          应用程序轮流来响应请求

最少连接    请求被分配到活动连接最少的服务器上

ip-hash     通过一个hash函数决定哪个服务器来响应用户的请求(依据客户端的session id)


1.下面是最简单的负载均衡的配置(轮询)


http {

    upstream server-pool {

        server srv1.example.com;

        server srv2.example.com;

        server srv3.example.com;

    }


    server {

        listen 80;


        location / {

            proxy_pass http://server-pool;

        }

    }

}


        上面这个配置中3个相同的应用程序的服务器srv1-srv3,默认的负载均衡方式是轮询,所用的请求通过反向代理给了server-pool组,nginx通过负载均衡来分发这些请求到三个服务上。


        在nginx中HTTP, HTTPS, FastCGI, uwsgi, SCGI, and memcached. 的负载均衡都是通过反向代理实现的。


要配置https的负载均衡只需要将http协议改https就可以了,其他配置不变。


要实现FastCGI, uwsgi, SCGI, or memcached的负载均衡可以分别使用 fastcgi_pass, uwsgi_pass, scgi_pass, and memcached_pass指令。


        另一种负载均衡方式是least-connected,在“请求需要更长的时间来完成”的场景下采用least-connected方式可以更公平的将负载分配到多个机器上面。使用least-connected,nginx不会将请求分发到繁忙的机器上面,而且将新的请求分发的较清闲的机器上面。


2.可以在 upstream {}模块中配置least_conn;指令来激活least-connected负载模式


upstream server-pool {

        least_conn;

        server srv1.example.com;

        server srv2.example.com;

        server srv3.example.com;

    }


        轮询和least-connected这两种负载均衡方式会将新的请求分发到不同的机器上,很难保证每个客户端会固定访问某一个服务器。


如果需要某个客户端只访问访问固定的一个服务器可以通过ip-hash负载均衡方式实现。


使用ip-hash时,客户端的ip作为一个散列的Key来决定服务器组中哪个服务器来响应请求,这种方式可以保证每个客户端每次访问的都是同一个服务器。


3.客户通过ip_hash指令来配置ip_hash负载均衡方式


upstream server-pool {

    ip_hash;

    server srv1.example.com;

    server srv2.example.com;

    server srv3.example.com;

 }


权重的负载均衡方式,在轮询的基础上为每个服务器配置权重可以保证某个服务器尽可能处理多的请求


upstream server-pool {

        server srv1.example.com weight=3;

        server srv2.example.com;

        server srv3.example.com;

    }


上面的配置中,如果有5个请求,有3个会分配到serv1上,有1个会分配到srv2上,有一个会分配到srv3上。如果不指定weight,默认是平的的。


负载均衡包含服务器的健康检查,如果某个请求被分配到了一个服务器上,服务器无法响应,那么nginx会标记它失败了,在短时间内,nginx是不会将之后的请求分配给标记失败的服务器。max_fails指令可以设置最大失败次数,默认是1,需要先设置了fail_timeout才行。fail_timeout指定响应时间超过多少秒就将服务器标记为失败。服务器标记失败后,nginx会使用几个客户端请求优雅地探测服务器,如果探测成功,则服务器标记成功。



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

tomcat server.xml 主配置文件详解 

server.xml 是 Tomcat 的主配置文件,主要完成如下两个目标:

         提供 Tomcat 组件的初始配置;

         说明 Tomcat 的结构,含义,使得 Tomcat 通过实例化组件完成起动及构建自身。 观察 server.xml,可以发现其中有如下的一些元素。


   (1)Server 元素:

   Server 元素是 server.xml 文件的最高级别的元素, Server 元素描述一个 Tomcat 服务器,一 般来说用户不用关心这个元素。一个 Server 元素一般会包括 Logger 和 ContextManager 两个 元素

         Logger:Logger 元素定义了一个日志对象,一个日志对象包含有如下属性: 1) name:表示这个日志对象的名称。 

2) path:表示这个日志对象包含的日志内容要输出到哪一个日志文件。 

3) verbosityLevel:表示这个日志文件记录的日志的级别。 一般来说,Logger 对象是对 Java Servlet、JSP 和 Tomcat 运行期事件的记录 

 

        ContextManager:ContextManager 定义了一组ContextInterceptors(ContextManager 的事件监听器) , RequestInterceptors(的事件监听器)、Contexts(Web 应用程序的上下文 目录)和它们的 Connectors(连接器)的结构和配置。ContextManager 包含如下一些属性: 

1) debug:记录日志记录调试信息的等级。 

2) home:webapps /、conf /、logs /和所有 Context 的根目录信息。这个属性的作用是从一个 不同于 TOMCAT _ HOME 的目录启动 Tomcat。 

3) workDir:Tomcat 工作目录。 ContextInterceptor 和 RequestInterceptors 两者都是监听 ContextManager 的特定事件的拦截 器。ContextInterceptor 监听 Tomcat 的启动和结束事件信息。而 RequestInterceptors 监听用户对服务器发出的请求信息。一般用户无需关心这些拦截器,对于开发人员需要了解这就是 全局性的操作得以实现的方法   


(2)Connector 元素:   

Connector(连接器)元素描述了一个到用户的连接,不管是直接由 Tomcat 到用户的浏览器 还是通过一个 Web 服务器。Tomcat 的工作进程和由不同的用户建立的连接传来的读/写信息 和请求/答复信息都是由连接器对象管理的。对连接器对象的配置中应当包含管理类、TCP/IP 端口等内容。   


(3)Context 元素:  

每一个 Context 都描述了一个 Tomcat 的 Web 应用程序的目录。这个对象包含以下属性: 

1)docBase。这是 Context 的目录。可以是绝对目录也可以是基于 ContextManage 的根目录的 相对目录。 

2)path。这是 Context 在 Web 服务时的虚拟目录位置和目录名。 

3)debug。日志记录的调试信息记录等级。 

4)reloadable。这是为了方便 Servlet 的开发人员而设置的,当这个属性开关打开的时候, Tomcat 将检查 Servlet 是否被更新而决定是否自动重新载入它