首页 > 代码库 > nginx+tomcat负载均衡策略

nginx+tomcat负载均衡策略

测试环境均为本地,测试软件为:

nginx-1.6.0,apache-tomcat-7.0.42-1,apache-tomcat-7.0.42-2,apache-tomcat-7.0.42-3

利用nginx做负载均衡,三台tomcat做WEB具体业务处理。

nginx配置nginx.conf:

#Nginx所用用户和组,window下不指定  
#user  niumd niumd;  
#user  nobody;

#工作的子进程数量(通常等于CPU数量或者2倍于CPU)
worker_processes  2;

#错误日志存放路径
#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;
    access_log  logs/access.log;  
  
    client_header_timeout  3m;  
    client_body_timeout    3m;  
    send_timeout           3m;  
   
    client_header_buffer_size    1k;  
    large_client_header_buffers  4 4k;  
 
 

    sendfile        on;
    tcp_nopush     on;
    tcp_nodelay     on;  

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    include    gzip.conf;  

    upstream localhost {  
      #根据ip计算将请求分配各那个后端tomcat,许多人误认为可以解决session问题,其实并不能。  
      #同一机器在多网情况下,路由切换,ip可能不同  
        
      server localhost:18081;  
      server localhost:18082;  
      server localhost:18083; 
      #根据IP做分配策略
      ip_hash; 
     }  
     #down 表示单前的server暂时不参与负载
     #weight  默认为1.weight越大,负载的权重就越大。
     #max_fails :允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误
     #fail_timeout:max_fails 次失败后,暂停的时间。
     #backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

    #nginx 的 upstream目前支持 4 种方式的分配 
    #1)、轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 
    #2)、weight 指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 
    #2)、ip_hash 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。  
    #3)、fair(第三方)按后端服务器的响应时间来分配请求,响应时间短的优先分配。  
    #4)、url_hash(第三方)
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / { 
            proxy_pass http://localhost;  
            proxy_redirect              off;
            proxy_set_header            Host $host;
            proxy_set_header            X-Real-IP $remote_addr;
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
            client_max_body_size        10m;	#允许客户端请求的最大单文件字节数  
            client_body_buffer_size     128k;	#缓冲区代理缓冲用户端请求的最大字节数,  
            proxy_connect_timeout       90;	#nginx跟后端服务器连接超时时间(代理连接超时)  
            proxy_send_timeout          90;	#后端服务器数据回传时间(代理发送超时)  
            proxy_read_timeout          90;	#连接成功后,后端服务器响应时间(代理接收超时)  
            proxy_buffer_size           4k;	#设置代理服务器(nginx)保存用户头信息的缓冲区大小
            proxy_buffers               4 32k;	#proxy_buffers缓冲区,网页平均在32k以下的话,这样设置  
            proxy_busy_buffers_size     64k;	#高负荷下缓冲大小(proxy_buffers*2)  
            proxy_temp_file_write_size  64k;	#设定缓存文件夹大小,大于这个值,将从upstream服务器传  
        }

        #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;
    #    }
    #}

}


Tomcat1配置server.xml:

<?xml version=‘1.0‘ encoding=‘utf-8‘?>

<Server port="18001" shutdown="SHUTDOWN">
 <Connector port="18081" protocol="HTTP/1.1"  connectionTimeout="20000"  redirectPort="18441" />
    <Connector port="18021" protocol="AJP/1.3" redirectPort="18441" />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
  </Service>
</Server>


Tomcat1配置server.xml:

<?xml version=‘1.0‘ encoding=‘utf-8‘?>

<Server port="18002" shutdown="SHUTDOWN">
 <Connector port="18082" protocol="HTTP/1.1"  connectionTimeout="20000"  redirectPort="18442" />
    <Connector port="18022" protocol="AJP/1.3" redirectPort="18442" />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
  </Service>
</Server>


Tomcat3配置server.xml:

<?xml version=‘1.0‘ encoding=‘utf-8‘?>

<Server port="18003" shutdown="SHUTDOWN">
 <Connector port="18083" protocol="HTTP/1.1"  connectionTimeout="20000"  redirectPort="18443" />
    <Connector port="18023" protocol="AJP/1.3" redirectPort="18443" />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
  </Service>
</Server>

分别启动三台tomcat,访问到地址依次是:http://localhost:18081;http://localhost:18082;http://localhost:18083

然后启动nginx,访问地址是:http://localhost

(cmd下面运行nginx.exe,关闭cmd下面运行nginx -s stop)


这样子根据客户端IP做负载均衡的同步策略已基本可满足需求,但是考虑到客户端多网卡或者客户端访问不同的服务器时产生session不同步的问题,需要使用memcached做session同步策略,后续我会跟上配置文档。

附:以下是来自于互联网的三中方法:
1、不用session,通过cookie等方式绕过session 。
      貌似这种方式还是会存在问题,假如客户端禁用cookie怎么办。
2、应用服务器自行实现共享
    如单点登录,采用中央认证服务器;或者memcache来存放后端服务器需要使用的公共数据。我曾经就有程序采用本地ehcache+memcache来缓存数据,其中ehcache缓存一些与他机无关的数据,memcache缓存一些公共数据,但这样往往也容易出现问题。
3、ip_hash方式解决session共享  
        nginx中的ip_hash技术能够将某个ip的请求定向到同一台后端,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash是在upstream配置中定义的, 配置方式样例:
upstream backend {  
  server 127.0.0.1:8080 ;  
  server 127.0.0.1:9090 ;  
   ip_hash;  
}  
 ip_hash是容易理解的,但是因为仅仅能用ip这个因子来分配后端,因此ip_hash是有缺陷的,不能在一些情况下使用:
     (1)/ nginx不是最前端的服务器。ip_hash要求nginx一定是最前端的服务器,否则nginx得不到正确ip,就不能根据ip作hash。譬如使用 的是squid为最前端,那么nginx取ip时只能得到squid的服务器ip地址,用这个地址来作分流是肯定错乱的。
      (2)/ nginx的后端还有其它方式的负载均衡。假如nginx后端又有其它负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一 台session应用服务器上。这么算起来,nginx后端只能直接指向应用服务器,或者再搭一个squid,然后指向应用服务器。最好的办法是用 location作一次分流,将需要session的部分请求通过ip_hash分流,剩下的走其它后端去。
      (3) upstream_hash(这种方式没有尝试过)  

下面是从网络上整理的关于nginx与apache的对比:

1、nginx与apache优缺点对比

nginx相对于apache的优点: 
(1)轻量级,同样起web 服务,比apache占用更少的内存及资源 
(2)抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能 
(3)高度模块化的设计,编写模块相对简单 
(4)社区活跃,各种高性能模块出品迅速啊 
apache 相对于nginx 的优点: 
(1)rewrite:比nginx 的rewrite 强大 
(2)动态页面:模块超多,基本想到的都可以找到 
(3)少bug ,nginx 的bug 相对较多 
(4)超稳定 

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

2、作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点 使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生 意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型. Nginx 作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多. 
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验. Nginx 是 一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到 7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够不间断服务的情况下进行软件版本的升级 . 

3、Nginx 配置简洁, Apache 复杂 
Nginx 静态处理性能比 Apache 高 3倍以上 
Apache 对 PHP 支持比较简单,Nginx 需要配合其他后端用 
Apache 的组件比 Nginx 多 
现在 Nginx 才是 Web 服务器的首选 

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

5、nginx处理静态文件好,耗费内存少.但无疑apache仍然是目前的主流,有很多丰富的特性.所以还需要搭配着来.当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式. 
apache有先天不支持多核心處理負載雞肋的缺點,建議使用nginx做前端,後端用apache。大型網站建議用nginx自代的集群功能

6、 从个人过往的使用情况来看,nginx的负载能力比apache高很多。最新的服务器也改用nginx了。而且nginx改完配置能-t测试一下配置有没有问题,apache重启的时候发现配置出错了,会很崩溃,改的时候都会非常小心翼翼现在看有好多集群站,前端nginx抗并发,后端apache集群, 配合的也不错。

7、nginx处理动态请求是鸡肋,一般动态请求要apache去做,nginx只适合静态和反向。 

8、從我個人的經驗來看,nginx是很不錯的前端服務器,負載性能很好,在老奔上開nginx,用webbench模擬10000個靜態文件請求毫不吃力。apache對php等語言的支持很好,此外apache有強大的支持網路,發展時間相對nginx更久.

9、 Nginx优于apache的主要两点:
(1).Nginx本身就是一个反向代理服务器 
(2).Nginx支持7层负载均衡;其他的当然,Nginx可能会比 apache支持更高的并发,但是根据NetCraft的统计,2011年4月的统计数据,Apache依然占有62.71%,而Nginx是 7.35%,因此总得来说,Aapche依然是大部分公司的首先,因为其成熟的技术和开发社区已经也是非常不错的性能。 

10、你对web server的需求决定你的选择。大 部分情况下nginx都优于APACHE,比如说静态文件处理、PHP-CGI的支持、反向代理功能、前端Cache、维持连接等等。在 Apache+PHP(prefork)模式下,如果PHP处理慢或者前端压力很大的情况下,很容易出现Apache进程数飙升,从而拒绝服务的现象。 

11、可以看一下nginx lua模块:https://github.com/chaoslaw...apache比nginx多的模块,可直接用lua实现apache是最流行的,why?大多数人懒得更新到nginx或者学新事物 

12、对于nginx,我喜欢它配置文件写的很简洁,正则配置让很多事情变得简单运行效率高,占用资源少,代理功能强大,很适合做前端响应服务器 

13、Apache在处理动态有优势,Nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是Apache吧