電商高并發(fā)秒殺2 Nginx反向代理負(fù)載均衡

1. 部署Nginx OpenResty

安裝部署Nginx
OpenResty將許多配置編譯成了一個(gè)二進(jìn)制包,內(nèi)部集成了許多nginx特性;
1、安裝openresty

1)通過在CentOS 系統(tǒng)中添加 openresty 倉(cāng)庫(kù),便于未來安裝或更新我們的軟件包(通過 yum update 命令)

sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

2)安裝openresty

sudo yum install openresty

3)安裝命令行工具 resty

sudo yum install openresty-resty

命令行工具 opm 在 openresty-opm 包里,而 restydoc 工具在 openresty-doc 包里頭。

4)查看openresty 倉(cāng)庫(kù)里頭的軟件包

sudo yum --disablerepo="*" --enablerepo="openresty" list available

在Nginx web服務(wù)器中:

location節(jié)點(diǎn)path:指定url映射key;
location節(jié)點(diǎn)內(nèi)容:root指定location path后對(duì)應(yīng)的根路徑,index指定默認(rèn)的訪問頁(yè);
sbin/nginx -c conf/nginx.conf啟動(dòng);
修改配置后直接sbin/nginx -s reload無縫重啟;
2.3 前端資源部署
打包上傳前端資源文件;
配置前端資源路由;
2.4 配置nginx反向代理
nginx動(dòng)靜分離服務(wù)器

location節(jié)點(diǎn)path特定resources:靜態(tài)資源路徑;
location節(jié)點(diǎn)其它路徑:動(dòng)態(tài)資源用;
如何使用動(dòng)態(tài)資源?
nginx做反向代理服務(wù)器

設(shè)置upstream server
設(shè)置動(dòng)態(tài)請(qǐng)求location為proxy pass路徑;


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    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;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    
    upstream backend_server{
    server 192.168.239.102 weight=1;
    server 192.168.239.103 weight=1;
    keepalive 30;  
    }
     
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
         
        location /resources/ {
            alias   /usr/local/openresty/nginx/html/resources/;
            index  index.html index.htm;
        }
        
        location / {
            proxy_pass http://backend_server;
            proxy_set_header Host $http_host:$proxy_port;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
            proxy_http_version 1.1;
            proxy_set_header Connection ""; 

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

}

$remote_addr
獲取到上一級(jí)代理的IP

如果想要通過X-Forwarded-For獲得用戶ip,就必須先使用proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 這樣就可以獲得用戶真實(shí)ip。

開啟tomcat access log(訪問日志)驗(yàn)證

application.properties
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.directory=/usr/local/www/miaosha/tomcat
server.tomcat.accesslog.pattern=%h  %l  %u  %t  "%r"  %s  %b  %D

netstat -an | grep 192.168.239.1 | wc -l
netstat -an | grep 192.168.239.1 | grep ESTABLISHED

2.Nginx高性能原因

Nginx高性能主要分為以下三點(diǎn):

epoll多路復(fù)用完成非阻塞式的IO操作;
master worker進(jìn)程模型,允許其進(jìn)行平滑重啟和配置,不會(huì)斷開和客戶端連接;
協(xié)程機(jī)制,完成單進(jìn)程單線程模型,并支持并發(fā)編程調(diào)用接口;

2.1 epoll多路復(fù)用(解決IO阻塞回調(diào)通知問題)

I/O多路復(fù)用就是通過一種機(jī)制,可以監(jiān)視多個(gè)描述符,一旦某個(gè)IO能夠讀寫,通知程序進(jìn)行相應(yīng)的讀寫操作。

I/O多路復(fù)用的場(chǎng)合

當(dāng)客戶處理多個(gè)描述字時(shí)(通常是交互式輸入和網(wǎng)絡(luò)套接字),必須使用I/O復(fù)用
如果一個(gè)TCP服務(wù)器既要處理監(jiān)聽套接字,又要處理已連接套接字,一般也要用到I/O復(fù)用
如果一個(gè)服務(wù)器即要處理TCP,又要處理UDP,一般要使用I/O復(fù)用

Java BIO模型

client和server之間通過tpc/ip建立聯(lián)系,javaclient只有等到所有字節(jié)流socket.write到字節(jié)流的緩沖之后,對(duì)應(yīng)的java client才會(huì)返回;若網(wǎng)絡(luò)很慢,緩沖區(qū)填滿之后,client就必須等待信息傳輸過去之后,使得緩沖區(qū)可以給上游去寫時(shí),才可達(dá)到直接返回的效果;

Linux select模型

Linux select模型,變更觸發(fā)輪訓(xùn)查詢,文件描述符有1024數(shù)量上限;一旦java server被喚醒,并且對(duì)應(yīng)的socket連接打上有變化的標(biāo)識(shí)之后,就代表已經(jīng)有數(shù)據(jù)可以讓你讀寫;

弊端:
輪詢效率低,有1024數(shù)量限制;

epoll模型

epoll是為了解決select和poll的輪詢方式效率低問題;

假設(shè)一個(gè)場(chǎng)景:
有100萬個(gè)客戶端同時(shí)與一個(gè)服務(wù)器進(jìn)程保持著TCP連接。而每一時(shí)刻,通常只有幾百上千個(gè)TCP連接是活躍的(事實(shí)上大部分場(chǎng)景都是這種情況)。如何實(shí)現(xiàn)這樣的高并發(fā)?

在select/poll時(shí)代,服務(wù)器進(jìn)程每次都把這100萬個(gè)連接告訴操作系統(tǒng)(從用戶態(tài)復(fù)制句柄數(shù)據(jù)結(jié)構(gòu)到內(nèi)核態(tài)),讓操作系統(tǒng)內(nèi)核去查詢這些套接字上是否有事件發(fā)生,輪詢完后,再將句柄數(shù)據(jù)復(fù)制到用戶態(tài),服務(wù)器應(yīng)用程序輪詢處理已發(fā)生的網(wǎng)絡(luò)事件,這一過程資源消耗較大。因此,select/poll一般只能處理幾千的并發(fā)連接。

epoll的設(shè)計(jì)和實(shí)現(xiàn)與select完全不同:

epoll通過在Linux內(nèi)核中申請(qǐng)一個(gè)簡(jiǎn)單的文件系統(tǒng)(文件系統(tǒng)一般由B+樹實(shí)現(xiàn))
把原先的select/poll調(diào)用分成了3個(gè)部分:

  1. 調(diào)用epoll_create()建立一個(gè)epoll對(duì)象(在epoll文件系統(tǒng)中為這個(gè)句柄對(duì)象分配資源);
  2. 調(diào)用epoll_ctl向epoll對(duì)象中添加這100萬個(gè)連接的套接字;
  3. 調(diào)用epoll_wait收集發(fā)生的事件的連接;
    實(shí)現(xiàn)上面說是的場(chǎng)景,只需要在進(jìn)程啟動(dòng)時(shí)建立一個(gè)epoll對(duì)象,然后在需要的時(shí)候向這個(gè)epoll對(duì)象中添加或者刪除連接。同時(shí),epoll_wait的效率也非常高,因?yàn)檎{(diào)用epoll_wait時(shí),并沒有一股腦的向操作系統(tǒng)復(fù)制這100萬個(gè)連接的句柄數(shù)據(jù),內(nèi)核也不需要去遍歷全部的連接。
2.2 master-worker進(jìn)程模型
2.2.1進(jìn)程模型

Nginx之所以為廣大碼農(nóng)喜愛,除了其高性能外,還有其優(yōu)雅的系統(tǒng)架構(gòu)。與經(jīng)典多線程模型相比,Nginx是經(jīng)典的多進(jìn)程模型。Nginx啟動(dòng)后以daemon的方式在后臺(tái)運(yùn)行,后臺(tái)進(jìn)程包含一個(gè)master進(jìn)程和多個(gè)worker進(jìn)程

Nginx多進(jìn)程模型如下所示:


Nginx多進(jìn)程模型

master進(jìn)程主要用來管理worker進(jìn)程,具體包括如下4個(gè)主要功能:
(1)接收來自外界的信號(hào)。
(2)向各worker進(jìn)程發(fā)送信號(hào)。
(3)監(jiān)控woker進(jìn)程的運(yùn)行狀態(tài)。
(4)當(dāng)woker進(jìn)程退出后(異常情況下),會(huì)自動(dòng)重新啟動(dòng)新的woker進(jìn)程。
woker進(jìn)程主要用來處理網(wǎng)絡(luò)事件,各個(gè)woker進(jìn)程之間是對(duì)等且相互獨(dú)立的,它們同等競(jìng)爭(zhēng)來自客戶端的請(qǐng)求,一個(gè)請(qǐng)求只可能在一個(gè)woker進(jìn)程中處理,woker進(jìn)程個(gè)數(shù)一般設(shè)置為機(jī)器CPU核數(shù)。

2.2.2進(jìn)程控制
    對(duì)Nginx進(jìn)程的控制主要是通過master進(jìn)程來做到的,主要有兩種方式:
    (1)手動(dòng)發(fā)送信號(hào)
    從圖1可以看出,master接收信號(hào)以管理眾woker進(jìn)程,那么,可以通過kill向master進(jìn)程發(fā)送信號(hào),比如kill -HUP pid用以通知Nginx從容重啟。所謂從容重啟就是不中斷服務(wù):master進(jìn)程在接收到信號(hào)后,會(huì)先重新加載配置,然后再啟動(dòng)新進(jìn)程開始接收新請(qǐng)求,并向所有老進(jìn)程發(fā)送信號(hào)告知不再接收新請(qǐng)求并在處理完所有未處理完的請(qǐng)求后自動(dòng)退出。
    (2)自動(dòng)發(fā)送信號(hào)
    可以通過帶命令行參數(shù)啟動(dòng)新進(jìn)程來發(fā)送信號(hào)給master進(jìn)程,比如./nginx -s reload用以啟動(dòng)一個(gè)新的Nginx進(jìn)程,而新進(jìn)程在解析到reload參數(shù)后會(huì)向master進(jìn)程發(fā)送信號(hào)(新進(jìn)程會(huì)幫我們把手動(dòng)發(fā)送信號(hào)中的動(dòng)作自動(dòng)完成)。當(dāng)然也可以這樣./nginx -s stop來停止Nginx。
nginx reload master進(jìn)程不會(huì)重啟,而是讓worker進(jìn)程重啟
image.png
2.2.3網(wǎng)絡(luò)事件
     Nginx采用異步非阻塞的方式來處理網(wǎng)絡(luò)事件,類似于[Libevent](http://blog.chinaunix.net/uid-22312037-id-3546904.html),具體過程如下圖:
Nginx網(wǎng)絡(luò)事件

master進(jìn)程先建好需要listen的socket后,然后再fork出多個(gè)woker進(jìn)程,這樣每個(gè)work進(jìn)程都可以去accept這個(gè)socket。當(dāng)一個(gè)client連接到來時(shí),所有accept的work進(jìn)程都會(huì)受到通知,但只有一個(gè)進(jìn)程可以accept成功,其它的則會(huì)accept失敗。Nginx提供了一把共享鎖accept_mutex來保證同一時(shí)刻只有一個(gè)work進(jìn)程在accept連接,從而解決驚群?jiǎn)栴}。當(dāng)一個(gè)worker進(jìn)程accept這個(gè)連接后,就開始讀取請(qǐng)求,解析請(qǐng)求,處理請(qǐng)求,產(chǎn)生數(shù)據(jù)后,再返回給客戶端,最后才斷開連接,這樣一個(gè)完成的請(qǐng)求就結(jié)束了。

2.3協(xié)程機(jī)制

一個(gè)線程可以有多個(gè)協(xié)程,協(xié)程是線程的內(nèi)存模型

依附于線程的內(nèi)存模型,切換開銷小;
遇阻塞及歸還執(zhí)行權(quán),代碼同步,調(diào)用新的不阻塞的協(xié)程;
無需加鎖;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容