Nginx+Tomcat集群实现反向代理负载均衡和Session复制

以前写过一篇Apache+Tomcat集群的文章,最近正好有空,把Nginx+Tomcat也写一下做为比较。

首先,用Nginx和Apache+Tomcat做集群的区别,我就直接从网上找了点资料。

主要区别在于,Apache是同步多进程模型,一个连接对应一个进程。Nginx是异步多进程模型,多个连接对应一个进程,这里的多个连接可以达到上万的级别,所以普遍认为,Nginx的性能更好。

Nginx:

  1. 轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源

  2. 抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比 apache 高很多,而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而 apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。

  3. nginx 处理静态文件好,静态处理性能比 apache 高三倍以上

  4. nginx 的设计高度模块化,编写模块相对简单

  5. nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃

  6. nginx 作为负载均衡服务器,支持 7 层负载均衡

  7. nginx 本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器

    扫描二维码关注公众号,回复: 2639885 查看本文章
  8. 启动特别容易, 并且几乎可以做到 7*24 不间断运行,即使运行数个月也不需要重新启动,还能够不间断服务的情况下进行软件版本的升级

  9. 社区活跃,各种高性能模块出品迅速

Apache:
  1. apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache

  2. apache 发展到现在,模块超多,基本想到的都可以找到

  3. apache 更为成熟,少 bug ,nginx 的 bug 相对较多

  4. apache 超稳定

  5. apache 对 PHP 支持比较简单,nginx 需要配合其他后端用

  6. apache 在处理动态请求有优势,nginx 在这方面是鸡肋,一般动态请求要 apache 去做,nginx 适合静态和反向。

  7. apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区

总结:

两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程

一般来说,需要性能的 web 服务,用 nginx 。如果不需要性能只求稳定,更考虑 apache ,后者的各种功能模块实现得比前者,例如 ssl 的模块就比前者好,可配置项多。epoll(freebsd 上是 kqueue ) 网络 IO 模型是 nginx 处理性能高的根本理由,但并不是所有的情况下都是 epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache 的 select 模型或许比 epoll 更高性能。当然,这只是根据网络 IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。

更为通用的方案是,前端 nginx 抗并发,后端 apache 集群,配合起来会更好。

--------------------------------------------------------------------------------------------------

下面介绍如何配置Nginx+Tomcat集群并做到Session复制:

一. Tomcat配置(Tomcat8):

1.conf/server.xml:

主要注意的是端口号(port)的设置,<Engine>中jvmRoute的设置,<Cluster>的注释放开。

<?xml version='1.0' encoding='utf-8'?>
<Server port="8075" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">
    <!-- 多个Tomcat的端口号不能相同,否则无法启动 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000" maxHttpHeaderSize="2000000"
               redirectPort="8444" />

    <Connector port="8072" protocol="AJP/1.3" redirectPort="8444" />
    <!-- 多个Tomcat的jvmRoute必须要设置且必须相同 -->
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">

      <!-- Cluster原本是被注释掉的,现在要放开 -->
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>


      <Realm className="org.apache.catalina.realm.LockOutRealm">
       
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true" reloadable="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

2.webapps/ROOT/WEB-INF/web.xml:

添加<distributable />

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
<distributable /> 
</web-app>
3.在webapps/ROOT/下添加testCluster.jsp:

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*" %>
<html><head><title>Cluster Test</title></head>
<body>
<%
  //HttpSession session = request.getSession(true);
  System.out.println(session.getId());
  out.println("<br> SESSION ID:" + session.getId()+"<br>");  
  // 如果有新的请求,则添加session属性
  String name = request.getParameter("name");
  if (name != null && name.length() > 0) {
     String value = request.getParameter("value");
     session.setAttribute(name, value);
  }  
    out.print("<b>Session List:</b>");  
    Enumeration<String> names = session.getAttributeNames();
    while (names.hasMoreElements()) {
        String sname = names.nextElement(); 
        String value = session.getAttribute(sname).toString();
        out.println( sname + " = " + value+"<br>");
        System.out.println( sname + " = " + value);
   }
%>
  <form action="testCluster.jsp" method="post">
    名称:<input type=text size=20 name="name">
     <br>
    值:<input type=text size=20 name="value">
     <br>
    <input type=submit value="提交">
   </form>

   <b>负载均衡测试:此为:Tomcat1上的文件,<font color=red>111111</font><b>
</body>
</html>
在复制到其他Tomcat下时,将下面这段改掉即可
<b>负载均衡测试:此为:Tomcat1上的文件,<font color=red>111111</font><b>
<b>负载均衡测试:此为:Tomcat2上的文件,<font color=red>222222</font><b>
4. 启动多个Tomcat。


二. Nginx配置(nginx-1.12.2):

1.conf/nginx.conf:

#user  nobody;
worker_processes  1;	#工作进程的个数,一般与计算机的cpu核数一致

#错误日志存放路径  
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#指定pid存放文件 
#pid        logs/nginx.pid;

events {
    #使用网络IO模型linux建议epoll,FreeBSD建议采用kqueue,window下不指定。  
    #use epoll;  

    worker_connections  1024;	#单个进程最大连接数(最大连接数=连接数*进程数)  
}


http {
    include       mime.types;	#文件扩展名与文件类型映射表  
    default_type  application/octet-stream;	#默认文件类型  

    #定义日志格式
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;	#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
    #tcp_nopush     on;

    #keepalive_timeout  0;	
    keepalive_timeout  65;	#长连接超时时间,单位是秒  

    #gzip  on;	#启用Gizp压缩  

    #服务器的集群  
    upstream  netitcast.com {  #服务器集群名字   
	#Nginx是如何实现负载均衡的,Nginx的upstream目前支持以下几种方式的分配
    	#1、轮询(默认)
    	#每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
    	#2、weight
    	#指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
    	#2、ip_hash
   	#每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
    	#3、fair(第三方)
    	#按后端服务器的响应时间来分配请求,响应时间短的优先分配。
    	#4、url_hash(第三方)
    	#按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。  
      #ip_hash; 
        server    192.168.8.23:8080  weight=1;#服务器配置   weight是权重的意思,权重越大,分配的概率越大。  
        server    192.168.8.23:8079  weight=2;  
    }   

    #当前的Nginx的配置  
    server {
        listen       8082;	#监听80端口,可以改成其他端口  
        server_name  localhost;	#当前服务的域名 

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass http://netitcast.com;  
            proxy_redirect default;  
	    proxy_connect_timeout 3; #nginx跟后端服务器连接超时时间(代理连接超时) 
            proxy_send_timeout 30; #后端服务器数据回传时间(代理发送超时) 
            proxy_read_timeout 30; #连接成功后,后端服务器响应时间(代理接收超时) 
            #root   html;
            #index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
2. 点击nginx.exe,启动Nginx:

3.我在Nginx的启动过程中,遇到过一闪而过,启动失败的情况,这时可以看一下错误日志 logs/error.log

提示的错误是:2018/01/25 11:07:24 [emerg] 456476#460620: bind() to 0.0.0.0:8081 failed (10013: An attempt was made to access a socket in a way forbidden by its access permissions)

这是因为端口被占用了,把8081端口的进程关掉或者换一个其他的端口即可。


三. 测试

我Nginx用的端口是8082,所以输入http://localhost:8082/testCluster.jsp

1.这是第一次显示的画面,Tomcat1代表这是第一个Tomcat的页面


2.这是第二次显示的画面,Tomcat2表示这是第二个Tomcat的页面,说明负载均衡已成功


3.接下来测试Session复制。根据Tomcat变换前后,SESSION ID都是D07D8BB95B783F8CAA83D94175D24846.jvm1可以判断出,这是同一个Session。

可以输入名称和值,看看在服务器切换后,Session中是否可以保存。


4. 可以看到,2=222保存了,但是现在仍然在Tomcat2上,看不出效果,再试一次。


5.这次切换到Tomcat1了,而且Session List里面的值都带过来了。再试试Tomcat1能否传回Tomcat2。


6.回到Tomcat2以后,SessionList中的值仍然保持,至此Session复制完全成功了。



猜你喜欢

转载自blog.csdn.net/sunroyi666/article/details/79163088