nginx tomcat负载均衡之文件上传访问策略

多服务器负载均衡的策略有多种,其中为目前大多数大型网站所采用的就是nginx做前端代理,后端链接多台jsp,php,cgi等网站服务器;

近来一个项目可能会存在较大大访问量(预期日均用户量50万,最大并发数5万),项目开发采用的语言是java,有一个网站管理后台(系统管理员用的,访问量不大),另外有50多个接口向外提供ios,android客户端访问,预设服务器运行环境是tomcat,为了适应大规模并发,需要在tomcat前端增加代理服务器,来做负载均衡,于是就开始采用nginx作为前端代理服务器。

 

测试时,部署了3台tomcat服务器,1台nginx服务器,其中一台tomcat服务器与nginx在同一机器上;三台机器的操作系统分别为centos6.2(nginx+tomcat)、redhat enterprise 6.0(tomcat+mysql)、window xp(tomcat);

 

一开始按照官方推荐配置,配置了upstream模块,采用webbench测试并发一个动态的jsp(参数校验,数据库访问),3万个并发被平均的分配至三个tomcat服务器中处理,失败率是0;但当采用真实环境测试时问题来了:登录时总是提示验证码输入不正确,看下三台服务器控制台输出,然来生成验证码和验证验证码的tomcat经常不一致,而又没有配置session共享策略,所以必然会造成无法登录,这个问题通过设置nginx转发登录模块至同一台服务器解决;另外一个非常棘手的问题,那就是客户端文件上传问题(客户端接口中有两个文件上传接口),文件上传一开始也是动态的均衡到每台服务器,但是会发现可能上传的时候使用的是a服务器,下载的时候使用的是b服务器,这就经常的导致客户端无法正常的下载文件。

 

关于文件上传问题我想详细描述下:

 

文件的上传只能由tomcat服务器做处理,包括创建缩略图,写入路径至数据库,所以无法采用nginx自带的文件上传模块;

文件需要能被接口直接访问,路径需要写入数据库

 

考虑到的几种解决方案;

 

1.采用负载均衡策略,文件上传动态的分配至tomcat服务器处理,数据库中文件路径填写nginx服务器上的文件文件路径,然后每台服务器定时和nginx服务器做文件同步,最终文件下载时使用nginx直接处理;

 

2.采用负载均衡策略,文件上传动态的分配至tomcat服务器处理,数据库中文件路径填写tomcat服务器文件路径,并加上特殊前缀(唯一对应此台tomcat服务器);文件下载时,nginx配置一个前缀转发规则,不同的前缀转发至具体tomcat服务器;

 

3.采用负载均衡策略,文件上传动态的分配至tomcat服务器处理,数据库中文件路径填写tomcat服务器上的文件文件路径,然后每台tomcat服务器定时互相文件同步,最终文件下载时使用nginx动态分配至tomcat直接处理;

 

4.文件的上传指定nginx服务器上的tomcat处理,下载使用nginx处理;

 

 

 

优劣暂时就不写了,理解下,后期再给出吧;最终采用的策略是4(最简单)

 

 

另外附上nginx配置文件:

 

 

 

Xml代码   收藏代码
  1. user  root;  
  2. worker_processes  2;  
  3.   
  4. error_log  logs/error.log;  
  5. #error_log  logs/error.log  notice;  
  6. #error_log  logs/error.log  info;  
  7.   
  8. pid        logs/nginx.pid;  
  9.   
  10.   
  11. events {  
  12.     worker_connections  4048;  
  13. }  
  14.   
  15.   
  16. http {  
  17.     include       mime.types;  
  18.     default_type  application/octet-stream;  
  19.   
  20.     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
  21.                       '$status $body_bytes_sent "$http_referer" '  
  22.                       '"$http_user_agent" "$http_x_forwarded_for"';  
  23.   
  24.     access_log  logs/access.log  main;  
  25.   
  26.     sendfile        on;  
  27.     tcp_nopush     on;  
  28.   
  29.     #keepalive_timeout  0;  
  30.     keepalive_timeout  65;  
  31.   
  32.     #gzip  on;  
  33.   
  34.     server {  
  35.         listen       80;  
  36.         server_name  localhost;  
  37.   
  38.         #charset koi8-r;  
  39.   
  40.         access_log  logs/host.access.log  main;  
  41.   
  42.       # location / {  
  43.       #     root   html;  
  44.       #     index  index.html index.htm;  
  45.       # }  
  46.   
  47.         #error_page  404              /404.html;  
  48.   
  49.         # redirect server error pages to the static page /50x.html  
  50.         #  
  51.         error_page   500 502 503 504  /50x.html;  
  52.         location = /50x.html {  
  53.             root   html;  
  54.         }  
  55.   
  56.         # proxy the PHP scripts to Apache listening on 127.0.0.1:80  
  57.         #  
  58.         #location ~ \.php$ {  
  59.         #    proxy_pass   http://127.0.0.1;  
  60.         #}  
  61.   
  62.         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000  
  63.         #  
  64.         #location ~ \.php$ {  
  65.         #    root           html;  
  66.         #    fastcgi_pass   127.0.0.1:9000;  
  67.         #    fastcgi_index  index.php;  
  68.         #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;  
  69.         #    include        fastcgi_params;  
  70.         #}  
  71.   
  72.         # deny access to .htaccess files, if Apache's document root  
  73.         # concurs with nginx's one  
  74.         #  
  75.         #location ~ /\.ht {  
  76.         #    deny  all;  
  77.         #}  
  78.     }  
  79.   
  80.      upstream 192.168.1.245{     
  81.        # ip_hash;  
  82.         server 127.0.0.1:8083;# weight=5;     
  83.        # server 192.168.1.250:8083 weight=4;     
  84.        # server 192.168.1.106:8082 weight=3;     
  85.        # server 192.168.0.1:8001;     
  86.     }  
  87.   
  88.     upstream 192.168.1.245_nofile{  
  89.        # ip_hash;  
  90.         server 127.0.0.1:8083 weight=5;  
  91.         server 192.168.1.250:8083 weight=4;  
  92.         server 192.168.1.106:8082 weight=3;  
  93.        # server 192.168.0.1:8001;  
  94.     }  
  95.     
  96.   
  97.     server {     
  98.         listen          80;     
  99.         server_name     192.168.1.245;     
  100.         access_log      logs/big.server.access.log main;     
  101.        # root /home/ky/apache-tomcat-6.0.33/webapps/ROOT/;          
  102.    
  103.         location / {     
  104.                 proxy_pass      http://192.168.1.245_nofile;     
  105.         }  
  106.          
  107.          
  108.        # location ~ ^/(images|javascript|js|css|flash|media|static)/  {       
  109.        #         root    /home/ky/apache-tomcat-6.0.33/webapps/ROOT/;   
  110.        #         expires 30d;       
  111.        # }            
  112.    
  113.         location ~ \.(jsp|php) {  
  114.                 proxy_pass      http://192.168.1.245;  
  115.         }  
  116.   
  117.         location ~ /fckeditor/~ {  
  118.                 proxy_pass      http://192.168.1.245;  
  119.         }  
  120.   
  121.   
  122.         location /user/info/updateIcon.action {  
  123.                 proxy_pass      http://192.168.1.245;  
  124.         }  
  125.    
  126.          location /photo/photoUpload.action {  
  127.                 proxy_pass      http://192.168.1.245;  
  128.         }  
  129.   
  130.         location /createCode {  
  131.                 proxy_pass      http://192.168.1.245;  
  132.         }  
  133.   
  134.         location ~ ^/admin/ {  
  135.                 proxy_pass      http://192.168.1.245;  
  136.         }  
  137.   
  138.         location ~\.(htm|html|gif|jpg|jpeg|png|ico|rar|css|js|zip|txt|flv|swf|doc|ppt|xls)   {  
  139.                root    /home/ky/apache-tomcat-6.0.33/webapps/ROOT/;  
  140.         }  
  141.      
  142.     }  
  143.   
  144.     # another virtual host using mix of IP-, name-, and port-based configuration  
  145.     #  
  146.     #server {  
  147.     #    listen       8000;  
  148.     #    listen       somename:8080;  
  149.     #    server_name  somename  alias  another.alias;  
  150.   
  151.     #    location / {  
  152.     #        root   html;  
  153.     #        index  index.html index.htm;  
  154.     #    }  
  155.     #}  
  156.   
  157.   
  158.     # HTTPS server  
  159.     #  
  160.     #server {  
  161.     #    listen       443;  
  162.     #    server_name  localhost;  
  163.   
  164.     #    ssl                  on;  
  165.     #    ssl_certificate      cert.pem;  
  166.     #    ssl_certificate_key  cert.key;  
  167.   
  168.     #    ssl_session_timeout  5m;  
  169.   
  170.     #    ssl_protocols  SSLv2 SSLv3 TLSv1;  
  171.     #    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;  
  172.     #    ssl_prefer_server_ciphers   on;  
  173.   
  174.     #    location / {  
  175.     #        root   html;  
  176.     #        index  index.html index.htm;  
  177.     #    }  
  178.     #}  
  179.   
  180. }  

 

其实个人感觉还有一个问题,那就是数据库缓存问题,服务器采用ssh三层框架开发的,hibernate缓存无法共享,可能会导致数据库操作的不一致,下周测试并找到解决方案,再贴出

 

2012-06-24

____________________________

 接上页:

1.这个配置中有个漏洞,那就是没有配置哪些目录是不允许直接访问的,在传统tomcat作为服务器的时候,tomcat本身的机制就禁止直接访问WEB-INF下的内容,但是在nginx中,由于配置了部分内容直接从nginx转发出去,这就导致了WEB-INF目录实际上可能会被暴露出去,一旦暴漏了,那么系统架构,源代码,数据库配置文件,系统配置文件等内容将一并泄露,这对于商业项目来讲会是致命的安全隐患,再次提醒自己以及相关人士,一定要配置不允许访问的目录

新版配置在上一版配置中增加了三行:

 

Java代码   收藏代码
  1. location ~ ^/WEB-INF/ {  
  2.            deny  all;  
  3.        }  

 

 

2.上页中提到hibernate缓存问题调研:如果配置了hibernate的cache*的话确实会造成nginx返回结果不同步的问题,在此建议如果采用nginx则不要再继续配置hibernate的缓存(其实就内网来讲,网速的影响可以忽略,需要担心的是数据库服务器的负载能否跟上)

 

当nginx解决了前端的负载均衡的时候,接下来的问题就是如果解决mysql数据的负载(如果配置了100台主机公用一个mysql)以及nginx的负载瓶颈(3万并发)

 

待续

 

2012-07-16

 

————————————————————————

 

接上页;

 

这几天在真实环境中使用了nginx,项目需求是这样的:

内网有两台tomcat,但对外只能已一个端口的形式出现,并且运行的服务是网站

 

所谓网站,那么一定会校验refer,并且jsp网页中都已经使用了base这个参数,页面输出到浏览器后的所有请求的开头将会以这个base参数作为http的开头,由于base 的值是通过java代码自动生成的,生成规则是依据请求来源去获取对应的server以及端口,那么按照上文的配置,将会使得jsp执行完成后,base的值中出现8081等没有开放的端口,这会导致网站的css,js,img等内容无法加载,网页显示出问题,而且后续的网页跳转均出现错误;

 

经仔细查询nginx的文档,发现了一处关键配置,那就是proxy_set_header Host;

它的作用是对代理的服务,设置http请求的header,使得通过代理转发的url和用户真实的访问nginx的参数一致

例如,这里加入我设置的proxy_set_header Host $host:8082;那么tomcat再接收到通过nginx转发的http请求后,会认为url来源是$host:8082,进一步推进的结果就是在jsp中的base参数的值将被设置为$host:8082;那么jsp页面加载完成后,后续的访问将以$host:8082为url前缀,也就是说访问是首先访问的还是nginx,然后再转发至tomcat,从而使得整个网页的访问变得更加流畅

 

proxy_set_header其实还可以设置其他的参数,这里没有用到,暂时就不做更多的探究

 

一份完整的配置代码贴出来:

Java代码   收藏代码
  1. user  root;  
  2. worker_processes  2;  
  3.   
  4.   
  5. error_log  /var/log/nginx/error.log warn;  
  6. pid        /var/run/nginx.pid;  
  7.   
  8.   
  9. events {  
  10.     worker_connections  1024;  
  11. }  
  12.   
  13.   
  14. http {  
  15.     include       mime.types;  
  16.     default_type  application/octet-stream;  
  17.   
  18.     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
  19.                       '$status $body_bytes_sent "$http_referer" '  
  20.                       '"$http_user_agent" "$http_x_forwarded_for"';  
  21.   
  22.     access_log  /var/log/nginx/access.log  main;  
  23.   
  24.     sendfile        on;  
  25.     tcp_nopush     on;  
  26.   
  27.     #keepalive_timeout  0;  
  28.     keepalive_timeout  65;  
  29.   
  30.     #gzip  on;  
  31.   
  32.     server {  
  33.         listen       80;  
  34.     server_name 192.168.1.104;  
  35.     }  
  36.   
  37.      upstream tb{     
  38.         server 127.0.0.1:8082;     
  39.     }  
  40.   
  41.     upstream EdianCompile{  
  42.         server 127.0.0.1:8082;  
  43.     }  
  44.   
  45.   
  46.     upstream heihei{  
  47.         server 127.0.0.1:8081;  
  48.     }  
  49.   
  50.     upstream advertise{  
  51.     server 59.174.130.202:8088;  
  52.     }  
  53.   
  54.        
  55.       
  56.   
  57.     server {     
  58.         listen          80;     
  59.         server_name     app.emapp.cn;     
  60.         access_log      /var/log/nginx/big.server.access.log main;     
  61.    
  62.         location / {     
  63.                 proxy_pass      http://heihei;  
  64.         proxy_set_header Host $host;     
  65.         }  
  66.          
  67.         location ~ ^/tb/ {  
  68.                 proxy_pass      http://tb;  
  69.                 proxy_set_header Host $host;  
  70.         }  
  71.   
  72.     location ~ ^/EdianCompile/ {  
  73.                 proxy_pass      http://EdianCompile;  
  74.         proxy_set_header Host $host;  
  75.         }  
  76.       
  77.     location ~ ^/phonecharge/ {  
  78.                 proxy_pass      http://heihei;  
  79.                 proxy_set_header Host $host;  
  80.         }     
  81.        
  82.     location ~ ^/yhqserver/ {  
  83.                 proxy_pass      http://heihei;  
  84.                 proxy_set_header Host $host;  
  85.         }  
  86.       
  87.      location ~ ^/eshopapp/ {  
  88.                 proxy_pass      http://heihei;  
  89.                 proxy_set_header Host $host;  
  90.         }  
  91.   
  92.      location ~ ^/Struts2/ {  
  93.                 proxy_pass      http://heihei;  
  94.                 proxy_set_header Host $host;  
  95.         }  
  96.   
  97.     location ~ ^/advertise/ {  
  98.                 proxy_pass      http://advertise;  
  99.                 proxy_set_header Host $host;  
  100.         }  
  101.   
  102.     }  
  103. }  
 

 

你可能感兴趣的:(nginx)