天天看点

nginx+tomcat实现负载均衡一.nginx简单介绍二.安装nginx和tomcat三.nginx配置四.负载均衡策略五. session共享六.关于限流七.vue打包dist放在nginx下的配置附录:

文章目录

  • 一.nginx简单介绍
  • 二.安装nginx和tomcat
  • 三.nginx配置
  • 四.负载均衡策略
    • 4.1 轮询
    • 4.2 最少连接
    • 4.3 权重
    • 4.4 ip_hash
  • 五. session共享
    • 5.1 不使用session,换作cookie
    • 5.2 应用服务器自行实现共享
    • 5.3 ip_hash
    • 5.4 upstream_hash
  • 六.关于限流
    • 6.1 ngx_http_limit_conn_module
    • 6.2 ngx_http_limit_req_module
  • 七.vue打包dist放在nginx下的配置
    • 7.1 配置文件
  • 附录:
    • 1.资料参考:
    • 2. 零星知识点:

一.nginx简单介绍

Nginx是一款轻量级兼备高性能的Http和反向代理服务器。所谓反向代理就是指在用户发起访问请求,由代理服务器接收,然后将请求转发给正式服务器,并且将正式服务器处理完的数据返回给客户端,此时代理服务器就表现为一个服务器。这么做看起来多经过了一步,稍显麻烦,但实则是好处多多.

  1. 热部署

    我个人觉得这个很不错。在master管理进程与worker工作进程的分离设计,使的Nginx具有热部署的功能,那么在7×24小时不间断服务的前提下,升级Nginx的可执行文件。也可以在不停止服务的情况下修改配置文件,更换日志文件等功能。

  2. 可以高并发连接

    这是一个很重要的一个特性!在这一个 互联网 快速发展, 互联网 用户数量不断增加,一些大公司、网站都需要面对高并发请求,如果有一个能够在峰值顶住10万以上并发请求的Server,肯定会得到大家的青睐。理论上,Nginx支持的并发连接上限取决于你的内存,10万远未封顶。

  3. 低的内存消耗

    在一般的情况下,10000个非活跃的HTTP Keep-Alive 连接在Nginx中仅消耗2.5M的内存,这也是Nginx支持高并发连接的基础。

  4. 处理响应请求很快

    在正常的情况下,单次请求会得到更快的响应。在高峰期,Nginx可以比其他的Web服务器更快的响应请求。

  5. 具有很高的可靠性

    Nginx是一个高可靠性的Web服务器,这也是我们为什么选择Nginx的基本条件,现在很多的网站都在使用Nginx,足以说明Nginx的可靠性。高可靠性来自其核心框架代码的优秀设计、模块设计的简单性;并且这些模块都非常的稳定。

二.安装nginx和tomcat

nginx的安装教程参见<使用fastDFS从头搭建文件服务器>;

tomcat的安装教程参见CentOS中的<阿里云centOS手工部署Java Web项目>.

三.nginx配置

常用命令:
#打开配置文件
# vi /usr/local/nginx/conf/nginx.conf
#查看nginx进程
#ps aux |grep nginx

# cd /usr/local/nginx/sbin/
# ./nginx 
或者直接:
启动
# /usr/local/nginx/sbin/nginx
停止
# /usr/local/nginx/sbin/nginx -s stop
重启
# /usr/local/nginx/sbin/nginx -s reload

其它命令
# ./nginx -s stop
# ./nginx -s quit
# ./nginx -s reload
           
#使用用户与安装用户保持一致,不然可能会报403 Forbidden,window下不指定  
user  root;
#启动进程,通常设置成和cpu的数量相等
worker_processes  1;

#工作模式及连接数上限
events {
    use   epoll;             #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能;使用网络IO模型linux建议epoll,FreeBSD建议采用kqueue,window下不指定。
    worker_connections  1024; #51200=1024*50,单个后台worker process进程的最大并发链接数
}

#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
     #设定mime类型,类型由mime.type文件定义
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    #设定日志格式
    #access_log    /var/log/nginx/access.log;

    #sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
    #必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.其主要作用是加快对静态文件的处理。默认情况下是开启(on)状态。
    sendfile        on;
    tcp_nopush     on;#属于nginx静态资源配置模块,把多个包一次性整合之后再发送给客户端,而不是一次次发,在sendfile开启的情况下,提高网络包的传输效率,可在http、server和location中配置,默认是关闭(off)状态。
    tcp_nodelay     on;#属于nginx静态配置模块,尽量的把包发送出去,不要等待,用在实时性有要求的场景。一般在keepalive连接下,提高网络                                包的传输实时性,可在http、server和location中配置,默认是开启(on)状态。看上去是和tcp_nopush相反的功能,但是两边都为on时nginx也可以平衡这两个功能的使用。

    #连接超时时间
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #设定负载均衡的服务器列表,这里的域名要和下面proxy_pass的一样
    upstream test {
        #weigth参数表示权值,权值越高被分配到的几率越大
        #本机上的Squid开启3128端口
        server 192.168.8.1:3128 weight=5;
        server 192.168.8.2:80  weight=1;
        server 192.168.8.3:80  weight=6;
    }
    server {
        #侦听80端口
        listen       80;
        
        #限制文件上传的大小,默认为1m,设为0表示无限制
        #client_max_body_size 32m;
        
        #定义使用www.xx.com访问,一般没什么用.目前知道的作用是虚拟主机:两个域名解析到同一个IP地址,监听同一个端口号,但是用户通过两个域名却可以打开两个完全不同的网站,互相不影响,就像访问两个服务器一样,所以叫两个虚拟主机。虚拟主机的原理是通过HTTP请求头中的Host是否匹配server_name来实现的
        server_name  test;

        #设定本虚拟主机的访问日志
        #access_log  logs/www.xx.com.access.log  main;

        #默认请求转发给后端服务器
        location / {
            #Host 这个不配置Request().getServerPort()拿到的端口会是默认的80
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass    http://test;    
        }
        #静态资源路径访问配置
        location ^~/static/ {
            alias  /var/www/static/;
            #或者用root  /var/www/;
        }
    }
}
           

四.负载均衡策略

4.1 轮询

这种是默认的策略,把每个请求按顺序逐一分配到不同的server,如果server挂掉,能自动剔除。

upstream  fengzp.com {   
    server   192.168.99.100:42000; 
    server   192.168.99.100:42001;  
}
           

4.2 最少连接

把请求分配到连接数最少的server

upstream  fengzp.com {   
    least_conn;
    server   192.168.99.100:42000; 
    server   192.168.99.100:42001;  
}
           

4.3 权重

使用weight来指定server访问比率,weight默认是1。以下配置会是server2访问的比例是server1的两倍。

upstream  fengzp.com {   
    server   192.168.99.100:42000 weight=1; 
    server   192.168.99.100:42001 weight=2;  
}
           

4.4 ip_hash

每个请求会按照访问ip的hash值分配,这样同一客户端连续的Web请求都会被分发到同一server进行处理,可以解决session的问题。如果server挂掉,能自动剔除。[如果只剩一个服务器了,ip_hash还是能访问到的,不用担心]

upstream  fengzp.com {   
    ip_hash;
    server   192.168.99.100:42000; 
    server   192.168.99.100:42001;  
}
           

ip_hash可以和weight结合使用。

五. session共享

5.1 不使用session,换作cookie

能把session改成cookie,就能避开session的一些弊端,在从前看的一本J2EE的书上,也指明在集群系统中不能用session,否则惹出祸端来就不好办。如果系统不复杂,就优先考虑能否将session去掉,改动起来非常麻烦的话,再用下面的办法。

5.2 应用服务器自行实现共享

asp.net可以用数据库或memcached来保存session,从而在asp.net本身建立了一个session集群,用这样的方式可以令 session保证稳定,即使某个节点有故障,session也不会丢失,适用于较为严格但请求量不高的场合。但是它的效率是不会很高的,不适用于对效率 要求高的场合。

以上两个办法都跟nginx没什么关系,下面来说说用nginx该如何处理:

5.3 ip_hash

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分流,剩下的走其它后端去。

5.4 upstream_hash

为了解决ip_hash的一些问题,可以使用upstream_hash这个第三方模块,这个模块多数情况下是用作url_hash的,但是并不妨碍将它用来做session共享。

六.关于限流

6.1 ngx_http_limit_conn_module

官方文档

  1. limit_conn_zone:
语法规则:[key可以是$binary_remote_addr,$server_name,$server_port,$uri等]
Syntax:	limit_conn_zone key zone=name:size;
Default:	—
Context:	http
           
  1. limit_conn:
语法规则:
Syntax:	limit_conn zone number;
Default:	—
Context:	http, server, location

           
  1. 示例:
http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    ...

    server {

        ...
    
        location /download/ {
            limit_conn addr 1;
        }
    }
    ...
}
        
           

6.2 ngx_http_limit_req_module

官方文档

  1. limit_req_zone
语法规则:
Syntax:	limit_req_zone key zone=name:size rate=rate [sync];
Default:	—
Context:	http
           
  1. limit_req
Syntax:	limit_req zone=name [burst=number] [nodelay | delay=number];
Default:	—
Context:	http, server, location
           
  1. 示例
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;#1r/s表示1秒钟一个请求,1r/m表示1分钟一个请求,但2r/m等价于30秒一个请求.如果想实现一分钟内瞬间接受两个请求,那就要用2r/m配合burst=1来实现了.

    ...

    server {

        ...

        location /search/ {
            limit_req zone=one burst=5 nodelay;
        }
    }
    ...
}
           
  • 酒店项目配置示例:
http {
    limit_req_zone $server_name zone=reqperserver:10m rate=2r/m;
    limit_conn_zone $server_name zone=perserver:10m;
    limit_conn_zone $uri zone=peruri:10m;

    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;
    tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  30;
    tcp_nodelay        on;

    #gzip  on;

    upstream hotelmanage.jsjunyi.com {
        ip_hash;
        #weigth参数表示权值,权值越高被分配到的几率越大
        #本机上的Squid开启3128端口
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
    }

    server {
        #设置文件上传大小限制
        client_max_body_size 200M;

        listen       8080;
        server_name  hotelmanage.jsjunyi.com;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location ^~/hotel/photo/ {
            alias  /data/hotel/photo/;
        }
        location ^~/hotel/uploads/software {
            #limit_req zone=reqperserver burst=1 nodelay;
            limit_rate 1000k;
            limit_conn perserver 3;
            #limit_conn peruri 3;
            alias  /data/hotel/software/;
        }
        location / {
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass    http://hotelmanage.jsjunyi.com;
        }
    }
}

#以上配置一个灵异的点在于:
location ^~/hotel/uploads/software
改为
location ^~/uploads/software
时是不起作用的,这就说明location配置的时候,最好从端口号之后就开始匹配.
           

七.vue打包dist放在nginx下的配置

7.1 配置文件

server {
        #侦听10010端口
        listen       9191;

        #限制文件上传的大小,默认为1m,设为0表示无限制
        client_max_body_size 200m;

        #定义使用www.xx.com访问
        server_name  10.58.21.170;

        #设定本虚拟主机的访问日志
        #access_log  logs/www.xx.com.access.log  main;

        location ^~/hotel/photo/ {
            alias  /data/hotel/photo/;
        }
        location ^~/hotel/uploads/software/ {
            alias  /data/hotel/software/;
        }
        #location /hotel/main/ {
        #    root /data/;
        #    index /hotel/dist/index.html;
        #    try_files $uri $uri/ /hotel/dist/index.html;
        #}
        #location /hotel/dist/ {
        #    alias /data/hotel/dist/;
        #}
        #前端路由配置,访问/fontEndHotel下的某个文件,找不到就返回/fontEndHotel/dist/index.html
        location /fontEndHotel/ {
            root /data/hotel/;
            index /fontEndHotel/dist/index.html;
            try_files $uri $uri/ /fontEndHotel/;#这里/fontEndHotel/也可以写成/fontEndHotel/dist/index.html
        }

        #默认请求转发给后端服务器
        location / {
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass    http://10.58.21.170;
        }
    }
    
#最重要的是做到前端路由和后端路由的区分,不能都是/hotel/...,这样就没办法用location进行区分,只要是区分开的,这边配置就简单了,就是两个location的事情.建议前端保持不变,后端不用hotel,用hotelapi之类的,前端毕竟是要展示在页面上的,用hotel比较好.
           

附录:

1.资料参考:

Nginx静态文件路径配置:root目录与alias目录的区别

使用Nginx实现Tomcat集群负载均衡

Nginx +tomcat 实现负载均衡集群

nginx反向代理后,jsp页面request.getServerPort()获取得端口号总是80解决方案

nginx+tomcat影响request值

Nginx http_limit_req模块详解

Nginx一种限流方案

nginx集群tomcat,session共享问题

NGINX 借助JEDIS 对TOMCAT做SESSION共享

2. 零星知识点:

  • 语法规则: location [=||*|^~] /uri/ { … }
= 开头表示精确匹配

^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。

~ 开头表示区分大小写的正则匹配

~* 开头表示不区分大小写的正则匹配

!~和!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则

/ 通用匹配,任何请求都会匹配到。

多个location配置的情况下匹配顺序为(参考资料而来,还未实际验证,试试就知道了,不必拘泥,仅供参考):

首先匹配 =,其次匹配^~, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
           
  • 服务器集群的名称不能包含下划线??
  • alias和root的区别:
root:真实的路径是root指定的值加上location指定的值。结尾的/可加可不加.
alias:指定的路径是location的别名,不管location的值怎么写,资源的真实路径都是 alias 指定的路径
           

继续阅读