1. 部署Nginx OpenResty
安裝部署Nginx
OpenResty將許多配置編譯成了一個二進制包暂吉,內(nèi)部集成了許多nginx特性;
1例隆、安裝openresty
1)通過在CentOS 系統(tǒng)中添加 openresty 倉庫,便于未來安裝或更新我們的軟件包(通過 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 倉庫里頭的軟件包
sudo yum --disablerepo="*" --enablerepo="openresty" list available
在Nginx web服務器中:
location節(jié)點path:指定url映射key;
location節(jié)點內(nèi)容:root指定location path后對應的根路徑,index指定默認的訪問頁;
sbin/nginx -c conf/nginx.conf啟動;
修改配置后直接sbin/nginx -s reload無縫重啟;
2.3 前端資源部署
打包上傳前端資源文件诞挨;
配置前端資源路由;
2.4 配置nginx反向代理
nginx動靜分離服務器
location節(jié)點path特定resources:靜態(tài)資源路徑呢蛤;
location節(jié)點其它路徑:動態(tài)資源用惶傻;
如何使用動態(tài)資源?
nginx做反向代理服務器
設置upstream server
設置動態(tài)請求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
獲取到上一級代理的IP
如果想要通過X-Forwarded-For獲得用戶ip银室,就必須先使用proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 這樣就可以獲得用戶真實ip。
開啟tomcat access log(訪問日志)驗證
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高性能主要分為以下三點:
epoll多路復用完成非阻塞式的IO操作静秆;
master worker進程模型粮揉,允許其進行平滑重啟和配置,不會斷開和客戶端連接抚笔;
協(xié)程機制扶认,完成單進程單線程模型,并支持并發(fā)編程調(diào)用接口殊橙;
2.1 epoll多路復用(解決IO阻塞回調(diào)通知問題)
I/O多路復用就是通過一種機制辐宾,可以監(jiān)視多個描述符,一旦某個IO能夠讀寫膨蛮,通知程序進行相應的讀寫操作叠纹。
I/O多路復用的場合
當客戶處理多個描述字時(通常是交互式輸入和網(wǎng)絡套接字),必須使用I/O復用
如果一個TCP服務器既要處理監(jiān)聽套接字敞葛,又要處理已連接套接字誉察,一般也要用到I/O復用
如果一個服務器即要處理TCP,又要處理UDP惹谐,一般要使用I/O復用
Java BIO模型
client和server之間通過tpc/ip建立聯(lián)系持偏,javaclient只有等到所有字節(jié)流socket.write到字節(jié)流的緩沖之后,對應的java client才會返回氨肌;若網(wǎng)絡很慢鸿秆,緩沖區(qū)填滿之后,client就必須等待信息傳輸過去之后怎囚,使得緩沖區(qū)可以給上游去寫時卿叽,才可達到直接返回的效果;
Linux select模型
Linux select模型,變更觸發(fā)輪訓查詢考婴,文件描述符有1024數(shù)量上限贩虾;一旦java server被喚醒,并且對應的socket連接打上有變化的標識之后蕉扮,就代表已經(jīng)有數(shù)據(jù)可以讓你讀寫整胃;
弊端:
輪詢效率低,有1024數(shù)量限制喳钟;
epoll模型
epoll是為了解決select和poll的輪詢方式效率低問題;
假設一個場景:
有100萬個客戶端同時與一個服務器進程保持著TCP連接在岂。而每一時刻奔则,通常只有幾百上千個TCP連接是活躍的(事實上大部分場景都是這種情況)。如何實現(xiàn)這樣的高并發(fā)蔽午?
在select/poll時代易茬,服務器進程每次都把這100萬個連接告訴操作系統(tǒng)(從用戶態(tài)復制句柄數(shù)據(jù)結(jié)構(gòu)到內(nèi)核態(tài)),讓操作系統(tǒng)內(nèi)核去查詢這些套接字上是否有事件發(fā)生及老,輪詢完后抽莱,再將句柄數(shù)據(jù)復制到用戶態(tài),服務器應用程序輪詢處理已發(fā)生的網(wǎng)絡事件骄恶,這一過程資源消耗較大食铐。因此,select/poll一般只能處理幾千的并發(fā)連接僧鲁。
epoll的設計和實現(xiàn)與select完全不同:
epoll通過在Linux內(nèi)核中申請一個簡單的文件系統(tǒng)(文件系統(tǒng)一般由B+樹實現(xiàn))
把原先的select/poll調(diào)用分成了3個部分:
- 調(diào)用epoll_create()建立一個epoll對象(在epoll文件系統(tǒng)中為這個句柄對象分配資源);
- 調(diào)用epoll_ctl向epoll對象中添加這100萬個連接的套接字;
- 調(diào)用epoll_wait收集發(fā)生的事件的連接;
實現(xiàn)上面說是的場景虐呻,只需要在進程啟動時建立一個epoll對象,然后在需要的時候向這個epoll對象中添加或者刪除連接寞秃。同時斟叼,epoll_wait的效率也非常高,因為調(diào)用epoll_wait時春寿,并沒有一股腦的向操作系統(tǒng)復制這100萬個連接的句柄數(shù)據(jù)朗涩,內(nèi)核也不需要去遍歷全部的連接。
2.2 master-worker進程模型
2.2.1進程模型
Nginx之所以為廣大碼農(nóng)喜愛绑改,除了其高性能外谢床,還有其優(yōu)雅的系統(tǒng)架構(gòu)。與經(jīng)典多線程模型相比绢淀,Nginx是經(jīng)典的多進程模型萤悴。Nginx啟動后以daemon的方式在后臺運行,后臺進程包含一個master進程和多個worker進程
Nginx多進程模型如下所示:
master進程主要用來管理worker進程皆的,具體包括如下4個主要功能:
(1)接收來自外界的信號覆履。
(2)向各worker進程發(fā)送信號。
(3)監(jiān)控woker進程的運行狀態(tài)。
(4)當woker進程退出后(異常情況下)硝全,會自動重新啟動新的woker進程栖雾。
woker進程主要用來處理網(wǎng)絡事件,各個woker進程之間是對等且相互獨立的伟众,它們同等競爭來自客戶端的請求析藕,一個請求只可能在一個woker進程中處理,woker進程個數(shù)一般設置為機器CPU核數(shù)凳厢。
2.2.2進程控制
對Nginx進程的控制主要是通過master進程來做到的账胧,主要有兩種方式:
(1)手動發(fā)送信號
從圖1可以看出,master接收信號以管理眾woker進程先紫,那么治泥,可以通過kill向master進程發(fā)送信號,比如kill -HUP pid用以通知Nginx從容重啟遮精。所謂從容重啟就是不中斷服務:master進程在接收到信號后居夹,會先重新加載配置,然后再啟動新進程開始接收新請求本冲,并向所有老進程發(fā)送信號告知不再接收新請求并在處理完所有未處理完的請求后自動退出准脂。
(2)自動發(fā)送信號
可以通過帶命令行參數(shù)啟動新進程來發(fā)送信號給master進程,比如./nginx -s reload用以啟動一個新的Nginx進程檬洞,而新進程在解析到reload參數(shù)后會向master進程發(fā)送信號(新進程會幫我們把手動發(fā)送信號中的動作自動完成)狸膏。當然也可以這樣./nginx -s stop來停止Nginx。
nginx reload master進程不會重啟疮胖,而是讓worker進程重啟
2.2.3網(wǎng)絡事件
Nginx采用異步非阻塞的方式來處理網(wǎng)絡事件环戈,類似于[Libevent](http://blog.chinaunix.net/uid-22312037-id-3546904.html),具體過程如下圖:
master進程先建好需要listen的socket后澎灸,然后再fork出多個woker進程院塞,這樣每個work進程都可以去accept這個socket。當一個client連接到來時性昭,所有accept的work進程都會受到通知拦止,但只有一個進程可以accept成功,其它的則會accept失敗糜颠。Nginx提供了一把共享鎖accept_mutex來保證同一時刻只有一個work進程在accept連接汹族,從而解決驚群問題。當一個worker進程accept這個連接后其兴,就開始讀取請求顶瞒,解析請求,處理請求元旬,產(chǎn)生數(shù)據(jù)后榴徐,再返回給客戶端守问,最后才斷開連接,這樣一個完成的請求就結(jié)束了坑资。
2.3協(xié)程機制
一個線程可以有多個協(xié)程耗帕,協(xié)程是線程的內(nèi)存模型
依附于線程的內(nèi)存模型,切換開銷懈ぶ仿便;
遇阻塞及歸還執(zhí)行權(quán),代碼同步攒巍,調(diào)用新的不阻塞的協(xié)程嗽仪;
無需加鎖;