天天看點

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 指定的路徑
           

繼續閱讀