Nginx+Tomcat 配置负载均衡

本文将使用Nginx+Tomcat的工具配置一个分布式集群环境,作为企业级开发最常见的集群搭建方式,Nginx+Tomcat由于简单方便,性能优秀,深受很多人的喜爱。为了方便起见,我暂时将集群搭建在本机的Windows系统上,一般企业级应用都是搭建在Linux,建议大家将环境搭建在Linux,来获得更好的性能。

一.搭建环境

操作系统:windows server 2008 64位

JDK 1.7

tomcat 7和 tomcat6 (下载地址:http://tomcat.apache.org/download-70.cgi)

Nginx1.8.0(下载地址:http://nginx.org/en/download.html ,下载nginx/Windows-1.8.0)

二.软件安装

1.安装JDK,jdk的安装过程网上有很多,随便搜一下就知道了,这里就不再重复;

2.安装Tomcat,建议大家不要下载安装包,下载zip版的,直接解压到一个目录下,如E:/web/server目录下,tomcat6和7各复制一份,一共形成4个tomcat组成集群,随便找一个的bin目录下点击startup.bat,启动后在浏览器上输入 http://localhost:8080 ,如果出现下面页面

,则说明安装成功!

3.安装Nginx,下载后得到一个zip的压缩包,解压缩放在一个文件夹下就行,这里我放在了E:/web文件夹下,nginx的目录结构为:



点击nginx.exe就启动了nginx服务器了,在浏览器上输入localhost,如果出现如下页面


就说明安装成功了。

三.集群配置

在nginx1.8.0目录下有一个conf文件夹,conf下面有一个nginx.conf文件,进行集群配置就是要在这个文件中进行:

#user  nobody;
#工作进程,一般小于等于cpu核心数量
worker_processes  1;

#进程绑定到cpu的位置
#worker_cpu_affinity 0001 0010;

events {
#每个进程允许的同时最大连接数
    worker_connections  200000;

    #Windows上没有非阻塞模式
    #use epoll
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #启动内核复制模式,提高io效率
    sendfile        on;
    
    #每个连接alive存活的最长时间
    keepalive_timeout  65;

    #启动内容压缩
    gzip  on;
    #内容大于多少才压缩
    gzip_min_length 1000;
    #压缩基本
    gzip_comp_level 4;
    #压缩内容类别
    gzip_types text/plain text/css application/json application/x-javascript text/xml;

    #静态文件缓存
    open_file_cache max=655350 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;

    upstream dunquan-tomcat {
	server 127.0.0.1:8080 weight=5;
	server 127.0.0.1:8081 weight=3;
    }

    server {
        listen       80;
        server_name  localhost;

        charset utf-8;

        location / {
            #root   html;
            proxy_pass   http://dunquan-tomcat;
	    proxy_set_header X-Real-IP $remote_addr;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
这是一个比较简单的配置,

upstream dunquan-tomcat {
	server 127.0.0.1:8080 weight=5;
	server 127.0.0.1:8081 weight=3;
    }
这里是设置一个简单的多个服务器的集群,你自己可以加多个服务器,weight是每个服务器的加权权重,这里是使用的加权轮询的方式进行负载均衡的,就是如果每来了8个请求,则5个分配给上面的服务器,3个分配给下面的服务器,此外,还有其他几种服务器分配算法,下面再介绍;

注意你如果多个服务器是在一个主机上,在tomcat的配置文件里你需要把tomat的几个监听端口设置成不同的,如:

<Server port="8006" shutdown="SHUTDOWN">
    <Connector port="8081" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
 <Connector port="8011" protocol="AJP/1.3" redirectPort="8443" />

nginx是使用反向代理的模式来处理请求的,每个请求需要发给nginx服务器,然后nginx服务器代理发送到具体的应用服务器,而且现在浏览器都是建立两条链路来发送请求,所以真正nginx最大同时连接数是 : worker_processes * worker_connections / 4
还有一点是:

    #Windows上没有非阻塞模式
    #use epoll
由于Linux上io处理的方式是非阻塞模式的,一般使用epoll模式,这种模式对网络io的处理具有非常好的性能,而Windows上没有epoll这种非阻塞模式的,所以nginx在Windows上面部署的性能远远没有Linux性能好,所以我建议大家在Linux上面搭建环境。

四.Session处理方式

session是储存在服务器端的会话,Session 对象存储特定用户会话所需的信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。

由此可知,session是存储在服务器端的,也就是tomcat服务器上,其实我们如果解析tomcat的源码,就可以发现tomcat服务器有一个专门的线程来维持session信息的,关于tomcat具体解析的问题我在另外一篇博客详细解析了,感兴趣的可以去看看。

session存储在tomcat端,这样的话假如我一个用户在服务器A登录了,A服务器中就有session信息,然后我下次请求nginx给我分配到B服务器,但是B服务器中没有我们session信息,这时就有问题了。

我们知道问题是如何出现的,那么问题的解决方案就也很清晰了:

方案一,既然A服务器中有某个用户的信息,那么就让这个用户一直访问A服务器就行了啊,所以通过ip得到一个hash值,根据hash值来转发到对应的服务器即可:

upstream dunquan-tomcat {
    ip_hash;
	server 127.0.0.1:8080;
	server 127.0.0.1:8081;
    }

这样就可以实现一个比较简单的session处理方案,但是这个方案可能有一个问题是如果服务器A挂掉了,那么这个服务器上的session信息就丢失了,可能会出现问题;

方案二 是既然各个服务器上的session信息不同步,那就让它同步好了,在tomcat上进行配置,如果一个服务器上的session状态发生任何改变,通知所有服务器上的session同时改变,这样也可以达到目的,且一台服务器挂掉对其他没有影响,但是让所有服务器维持所有session的状态,会导致服务器的性能有所下降;

方案三 是把session信息专门存放在另外的一个地方,如memcached缓存中,当某台服务器的session状态发生改变时,同步只用改变memcached的session信息就行,取也是直接到memcached中取,这样就比较好的解决了服务器挂掉session出问题和性能问题。由于在Windows上安装memcached比较麻烦,这里就不具体演示了。

五.其他

最后,当我们在tomcat上开启具体的项目,然后在浏览器中输入localhost/stuallList时(这是我的请求和页面,你的是你自己的项目),我们能观察到


就说明我们的负载均衡成功了。


还有一些需要注意的是由于nginx使用了反向代理,所以request.getRemoteAddr()这个方法获取的ip地址是nginx的地址,如果需要获取具体的用户ip地址,需要在nginx.conf文件中设置

proxy_set_header        X-Real-IP       $remote_addr;

然后在项目中使用request.getHeader("X-Real-IP")方式来获取用户ip。



猜你喜欢

转载自blog.csdn.net/ningdunquan/article/details/50572011