Nginx 的這些妙用

Nginx 簡介

Nginx 是一個免費、開源、高性能、輕量級的 HTTP 和反向代理服務器,也是一個電子郵件(IMAP/POP3)代理服務器,其特點是佔有內存少,併發能力強。

Nginx 由內核和一系列模塊組成,內核提供 Web 服務的基本功能,如啟用網絡協議,創建運行環境,接收和分配客戶端請求,處理模塊之間的交互。

Nginx 的各種功能和操作都由模塊來實現。Nginx 的模塊從結構上分為:

  • 核心模塊:HTTP 模塊、EVENT 模塊和 MAIL 模塊。
  • 基礎模塊:HTTP Access 模塊、HTTP FastCGI 模塊、HTTP Proxy 模塊和 HTTP Rewrite 模塊。
  • 第三方模塊:HTTP Upstream Request Hash 模塊、Notice 模塊和 HTTP Access Key 模塊及用戶自己開發的模塊。

這樣的設計使 Nginx 方便開發和擴展,也正因此才使得 Nginx 功能如此強大。

Nginx 的模塊默認編譯進 Nginx 中,如果需要增加或刪除模塊,需要重新編譯 Nginx,這一點不如 Apache 的動態加載模塊方便。

如果有需要動態加載模塊,可以使用由淘寶網發起的 Web 服務器 Tengine,在 Nginx 的基礎上增加了很多高級特性,完全兼容 Nginx,已被國內很多網站採用。

Nginx 有很多擴展版本:

  • 開源版 nginx.org
  • 商業版 NGINX Plus
  • 淘寶網發起的 Web 服務器 Tengine
  • 基於 Nginx 和 Lua 的 Web 平臺 OpenResty

Nginx 作為 Web 服務器

Web 服務器也稱為 WWW(World Wide Web)服務器,主要功能是提供網上信息瀏覽服務,常常以 B/S(Browser/Server)方式提供服務:

  • 應用層使用 HTTP 協議。
  • HTML 文檔格式。
  • 瀏覽器統一資源定位器(URL)。

Nginx 可以作為靜態頁面的 Web 服務器,同時還支持 CGI 協議的動態語言,比如 Perl、PHP 等,但是不支持 Java。

Java 程序一般都通過與 Tomcat 配合完成。作為一名 Java 程序員,肯定要理解下 Nginx 和 Tomcat 的區別了。

Nginx、Apache 和 Tomcat:

  • Nginx:由俄羅斯程序員 Igor Sysoev 所開發的輕量級、高併發 HTTP 服務器。
  • Apache HTTP Server Project:一個 Apache 基金會下的 HTTP 服務項目,和 Nginx 功能類似。
  • Apache Tomcat:是 Apache 基金會下的另外一個項目,是一個 Application Server。更準確的說是一個 Servlet 應用容器,與 Apache HTTP Server 和 Nginx 相比,Tomcat 能夠動態的生成資源並返回到客戶端。

Apache HTTP Server 和 Nginx 本身不支持生成動態頁面,但它們可以通過其他模塊來支持(例如通過 Shell、PHP、Python 腳本程序來動態生成內容)。

一個 HTTP Server 關心的是 HTTP 協議層面的傳輸和訪問控制,所以在 Apache/Nginx 上你可以看到代理、負載均衡等功能。

客戶端通過 HTTP Server 訪問服務器上存儲的資源(HTML 文件、圖片文件等等)。

通過 CGI 技術,也可以將處理過的內容通過 HTTP Server 分發,但是一個 HTTP Server 始終只是把服務器上的文件如實的通過 HTTP 協議傳輸給客戶端。

而應用服務器,則是一個應用執行的容器。它首先需要支持開發語言的運行(對於 Tomcat 來說,就是 Java),保證應用能夠在應用服務器上正常運行。

其次,需要支持應用相關的規範,例如類庫、安全方面的特性。對於 Tomcat 來說,就是需要提供 JSP/Sevlet 運行需要的標準類庫、Interface 等。

為了方便,應用服務器往往也會集成 HTTP Server 的功能,但是不如專業的 HTTP Server 那麼強大。

所以應用服務器往往是運行在 HTTP Server 的背後,執行應用,將動態的內容轉化為靜態的內容之後,通過 HTTP Server 分發到客戶端。

正向代理

正向代理:如果把局域網外的 Internet 想象成一個巨大的資源庫,則局域網中的客戶端要訪問 Internet,則需要通過代理服務器來訪問,這種代理服務就稱為正向代理。

正向代理“代理”的是客戶端。比如你想去 Google 看個“動作片”,可國內不允許呀,就需要找翻牆代理,這個就是所謂的“正向代理”。

Nginx 的這些妙用

反向代理與負載均衡

反向代理正好與正向代理相反,反向代理是指以代理服務器來接收 Internet 上的連接請求,然後將請求轉發到內部網絡上的服務器,並將服務器上得到的結果返回給客戶端。

此時代理服務器對外表現就是一個服務器,客戶端對代理是無感知的。反向代理“代理”的是服務端。

再比如,你想本本分分的在“優酷”上看個“愛情片”,youku.com 會把你的請求分發到存放片片的那臺機器上,這個就是所謂的“反向代理”。

Nginx 的這些妙用

為什麼使用反向代理,原因如下:

  • 保護和隱藏原始資源服務器
  • 加密和 SSL 加速
  • 通過緩存靜態資源,加速 Web 請求
  • 實現負載均衡

負載均衡:TODO: 留一個負載均衡詳細介紹傳送門。

地址重定向:Nginx 的 Rewrite 主要的功能就是實現 URL 重寫,比如輸入 360.com 跳轉到了 360.cn,baidu.cn 跳轉到了 baidu.com。

動靜分離

為了加快網站的解析速度,可以把動態頁面和靜態頁面由不同的服務器來解析,加快解析速度,降低原來單個服務器的壓力。

這裡指的就是讓動態程序(Java、PHP)去訪問應用服務器,讓緩存、圖片、JS、CSS 等去訪問 Nginx。

Nginx 安裝

①下載Nginx:

wgethttp://nginx.org/download/nginx-1.16.1.tar.gz

②安裝需要編譯的插件:

  • 用於編譯 C、C++ 代碼的 GCC。
  • 用 C 語言編寫的正則表達式函數庫 Pcre(使用 Rewrite 模塊)。
  • 用於數據壓縮的函式庫的 Zlib。
  • 安全套接字層密碼庫 OpenSSL(啟用 SSL 支持)。
yuminstallgccc++yuminstall-ypcrepcre-develyuminstall-yzlibzlib-develyuminstall-yopensslopenssl-devel

③解壓、配置(Nginx 支持各種配置選項 )、編譯、安裝 Nginx:

tar-zxvfnginx-1.15.tar.gzcdnginx-1.16.1cdnginx-1.16.1./configuremake&&sudomakeinstall

④啟動、重啟、關閉:

cd/usr/local/nginx/cdsbin./nginx#關閉命令./nginx-sstop#重啟,熱部署./nginx-sreload#修改配置文件後也別嘚瑟,反正我會動不動就寫錯,檢查修改的nginx.conf配置是否正確./nginx-t 
Nginx 的這些妙用

⑤驗證(瀏覽器輸入 IP):

Nginx 的這些妙用

配置文件

nginx.conf 配置文件主要分為三部分:

  • 全局塊
  • Events 塊
  • HTTPS 塊

Nginx 配置語法:

  • 配置文件由指令和指令塊構成
  • 每條指令以分號(;)結尾,指令和參數間以空格符分隔
  • 指令塊以大括號{}將多條指令組織在一起
  • include 語句允許組合多個配置文件以提高可維護性
  • 使用 # 添加註釋
  • 使用 $ 定義變量
  • 部分指令的參數支持正則表達式

全局塊

全局配置部分用來配置對整個 Server 都有效的參數。主要會設置一些影響 Nginx 服務器整體運行的配置指令,包括配置運行 Nginx 服務器的用戶(組)、允許生成的 Worker Process 數,進程 PID 存放路徑、日誌存放路徑和類型以及配置文件的引入等。

示例如下:

usernobody;worker_processes4;error_log/data/nginx/logs/error.lognotice;

Events 塊

Events 塊涉及的指令主要影響 Nginx 服務器與用戶的網絡連接,常用的設置包括是否開啟對多 Work Process 下的網絡連接進行序列化,是否允許同時接收多個網絡連接,選取哪種事件驅動模型來處理連接請求,每個 Word Process 可以同時支持的最大連接數等。

events{#每個workprocess支持的最大連接數為1024.worker_connections1024;}

HTTP 塊

這算是 Nginx 服務器配置中最頻繁的部分,代理、緩存和日誌定義等絕大多數功能和第三方模塊的配置都在這裡。 需要注意的是:HTTP 塊也可以包括 HTTP 全局塊、Server 塊。

①HTTP 全局塊

HTTP 全局塊配置的指令包括文件引入、MIME-TYPE 定義、日誌自定義、連接超時時間、單鏈接請求數上限等。

http{includemime.types;default_typeapplication/octet-stream;sendfileon;keepalive_timeout65;
②Server 塊

這塊和虛擬主機有密切關係,虛擬主機從用戶角度看,和一臺獨立的硬件主機是完全一樣的,該技術的產生是為了節省互聯網服務器硬件成本。

每個 HTTP 塊可以包括多個 Server 塊,而每個 Server 塊就相當於一個虛擬主機。

而每個 Server 塊也分為全局 Server 塊,以及可以同時包含多個 Locaton 塊。

全局 Server 塊:也被叫做“虛擬服務器”部分,它描述的是一組根據不同server_name指令邏輯分割的資源,這些虛擬服務器響應 HTTP 請求,因此都包含在 HTTP 部分。

最常見的配置是本虛擬機主機的監聽配置和本虛擬主機的名稱或 IP 配置。

server{listen80;#server_name也支持通配符,*.example.com、www.example.*、.example.comserver_namelocalhost;#charsetkoi8-r;#access_loglogs/host.access.logmain; 

Location 塊:一個 Server 塊可以配置多個 Location 塊。

這塊的主要作用是基於 Nginx 服務器接收到的請求字符串(例如 server_name/uri-string),對虛擬主機名稱 (也可以是 IP 別名)之外的字符串(例如前面的 /uri-string)進行匹配,對特定的請求進行處理。

地址定向、數據緩存和應答控制等功能,還有許多第三方模塊的配置也在這裡進行。

Location 指令說明:該指令用於匹配 URL。

語法如下:

location[=|~|~*|^~]uri{}
  • = :該修飾符使用精確匹配並且終止搜索。
  • ~:該修飾符使用區分大小寫的正則表達式匹配。
  • ~*:該修飾符使用不區分大小寫的正則表達式匹配。
  • ^~:用於不含正則表達式的 URI 前,要求 Nginx 服務器找到標識 URI 和請求字符串匹配度最高的 Location 後,立即使用此 Location 處理請求,而不再使用 Location 塊中的正則 URI 和請求字符串做匹配。

?>Tip 注意:如果 URI 包含正則表達式,則必須要有 ~ 或者 ~* 標識。

當一個請求進入時,URI 將會被檢測匹配一個最佳的 Location:

  • 沒有正則表達式的 Location 被作為最佳的匹配,獨立於含有正則表達式的 Location 順序。
  • 在配置文件中按照查找順序進行正則表達式匹配。在查找到第一個正則表達式匹配之後結束查找。由這個最佳的 Location 提供請求處理。
location/{roothtml;indexindex.htmlindex.htm;}#error_page404/404.html;#redirectservererrorpagestothestaticpage/50x.html#error_page500502503504/50x.html;location=/50x.html{roothtml;}location/{#try_files指令將會按照給定的參數順序進行匹配嘗試try_files$uri$uri//index.html;}

nginx.conf 詳細配置如下:

#定義Nginx運行的用戶和用戶組userwwwwww;#nginx進程數,通常設置成和cpu的數量相等worker_processes4;#全局錯誤日誌定義類型,[debug|info|notice|warn|error|crit]#error_log/data/nginx/logs/error.log;#error_log/data/nginx/logs/error.lognotice;#日誌文件存放路徑access_logpath[format[buffer=size|off]]access_log/data/nginx/logs/lazyegg.com/web/access.logcombinedio;#進程pid文件#pidlogs/nginx.pid;#指定進程可以打開的最大描述符:數目#工作模式與連接數上限##這個指令是指當一個nginx進程打開的最多文件描述符數目,理論值應該是最多打開文件數(ulimit -n)與nginx進程數相除,但是nginx分配請求並不是那麼均勻,所以最好與ulimit -n 的值保持一致。#這是因為nginx調度時分配請求到進程並不是那麼的均衡,所以假如填寫10240,總併發量達到3-4萬時就有進程可能超過10240了,這時會返回502錯誤。worker_rlimit_nofile65535;#################################events###############################events{#參考事件模型,use[kqueue|rtsig|epoll|/dev/poll|select|poll];epoll模型useepoll#單個進程最大連接數(最大連接數=連接數+進程數)worker_connections1024;#keepalive超時時間keepalive_timeout60;#客戶端請求頭部的緩衝區大小。client_header_buffer_size4k;#這個將為打開文件指定緩存,默認是沒有啟用的,max指定緩存數量,建議和打開文件數一致,inactive是指經過多長時間文件沒被請求後刪除緩存。open_file_cachemax=65535inactive=60s;#這個是指多長時間檢查一次緩存的有效信息。open_file_cache_valid80s;#open_file_cache指令中的inactive參數時間內文件的最少使用次數,如果超過這個數字,文件描述符一直是在緩存中打開的,如上例,如果有一個文件在inactive時間內一次沒被使用,它將被移除。open_file_cache_min_uses1;#語法:open_file_cache_errorson|off默認值:open_file_cache_errorsoff使用字段:http,server,location這個指令指定是否在搜索一個文件是記錄cache錯誤.open_file_cache_errorson;}##############################http###################################設定http服務器,利用它的反向代理功能提供負載均衡支持http{#文件擴展名與文件類型映射表includemime.types;#默認文件類型default_typeapplication/octet-stream;#默認編碼charsetutf-8;#服務器名字的hash表大小server_names_hash_bucket_size128;#客戶端請求頭部的緩衝區大小。client_header_buffer_size32k;#客戶請求頭緩衝大小。large_client_header_buffers464k;#允許客戶端請求的最大單個文件字節數client_max_body_size8m;#開啟高效文件傳輸模式,sendfile指令指定nginx是否調用sendfile函數來輸出文件,對於普通應用設為 on,如果用來進行下載等應用磁盤IO重負載應用,可設置為off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。sendfileon;#開啟目錄列表訪問,適合下載服務器,默認關閉。autoindexon;#此選項允許或禁止使用socke的TCP_CORK的選項,此選項僅在使用sendfile的時候使用tcp_nopushon;tcp_nodelayon;#長連接超時時間,單位是秒keepalive_timeout120;#FastCGI相關參數是為了改善網站的性能:減少資源佔用,提高訪問速度。下面參數看字面意思都能理解。fastcgi_connect_timeout300;fastcgi_send_timeout300;fastcgi_read_timeout300;fastcgi_buffer_size64k;fastcgi_buffers464k;fastcgi_busy_buffers_size128k;fastcgi_temp_file_write_size128k;#gzip模塊設置gzipon;#開啟gzip壓縮輸出gzip_min_length1k;#最小壓縮文件大小gzip_buffers416k;#壓縮緩衝區gzip_http_version1.0;#壓縮版本(默認1.1,前端如果是squid2.5請使用1.0)gzip_comp_level2;#壓縮等級gzip_typestext/plainapplication/x-javascripttext/cssapplication/xml;#壓縮類型,默認就已經包含textml,所以下面就不用再寫了,寫上去也不會有問題,但是會有一個warn。gzip_varyon;#開啟限制IP連接數的時候需要使用#limit_zonecrawler$binary_remote_addr10m;#負載均衡配置upstreamlazyegg.net{#upstream的負載均衡,weight是權重,可以根據機器配置定義權重。weigth參數表示權值,權值越高被分配到的幾率越大。server192.168.80.121:80weight=3;server192.168.80.122:80weight=2;server192.168.80.123:80weight=3;#nginx的upstream目前支持4種方式的分配#1、輪詢(默認)#每個請求按時間順序逐一分配到不同的後端服務器,如果後端服務器down掉,能自動剔除。#2、weight#指定輪詢幾率,weight和訪問比率成正比,用於後端服務器性能不均的情況。#例如:#upstreambakend{#server192.168.0.14weight=10;#server192.168.0.15weight=10;#}#2、ip_hash#每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決session的問題。#例如:#upstreambakend{#ip_hash;#server192.168.0.14:88;#server192.168.0.15:80;#}#3、fair(第三方)#按後端服務器的響應時間來分配請求,響應時間短的優先分配。#upstreambackend{#serverserver1;#serverserver2;#fair;#}#4、url_hash(第三方)#按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器,後端服務器為緩存時比較有效。#例:在upstream中加入hash語句,server語句中不能寫入weight等其他的參數,hash_method是使用的hash算法#upstreambackend{#serversquid1:3128;#serversquid2:3128;#hash$request_uri;#hash_methodcrc32;#}#tips:#upstreambakend{#定義負載均衡設備的Ip及設備狀態}{#ip_hash;#server127.0.0.1:9090down;#server127.0.0.1:8080weight=2;#server127.0.0.1:6060;#server127.0.0.1:7070backup;#}#在需要使用負載均衡的server中增加proxy_passhttp://bakend/;#每個設備的狀態設置為:#1.down表示單前的server暫時不參與負載#2.weight為weight越大,負載的權重就越大。#3.max_fails:允許請求失敗的次數默認為1.當超過最大次數時,返回proxy_next_upstream模塊定義的錯誤#4.fail_timeout:max_fails次失敗後,暫停的時間。#5.backup:其它所有的非backup機器down或者忙的時候,請求backup機器。所以這臺機器壓力會最輕。#nginx支持同時設置多組的負載均衡,用來給不用的server來使用。#client_body_in_file_only設置為On可以講clientpost過來的數據記錄到文件中用來做debug#client_body_temp_path設置記錄文件的目錄可以設置最多3層目錄#location對URL進行匹配.可以進行重定向或者進行新的代理負載均衡}#虛擬主機的配置server{#監聽端口listen80;#域名可以有多個,用空格隔開server_namelazyegg.net;#默認入口文件名稱indexindex.htmlindex.htmindex.php;root/data/www/lazyegg;#對******進行負載均衡location~.*.(php|php5)?${fastcgi_pass127.0.0.1:9000;fastcgi_indexindex.php;includefastcgi.conf;}#圖片緩存時間設置location~.*.(gif|jpg|jpeg|png|bmp|swf)${expires10d;}#JS和CSS緩存時間設置location~.*.(js|css)?${expires1h;}#日誌格式設定#$remote_addr與$http_x_forwarded_for用以記錄客戶端的ip地址;#$remote_user:用來記錄客戶端用戶名稱;#$time_local:用來記錄訪問時間與時區;#$request:用來記錄請求的url與http協議;#$status:用來記錄請求狀態;成功是200,#$body_bytes_sent :記錄發送給客戶端文件主體內容大小;#$http_referer:用來記錄從那個頁面鏈接訪問過來的;#$http_user_agent:記錄客戶瀏覽器的相關信息;#通常web服務器放在反向代理的後面,這樣就不能獲取到客戶的IP地址了,通過$remote_add拿到的IP地址是反向代理服務器的iP地址。反向代理服務器在轉發請求的http頭信息中,可以增加x_forwarded_for信息,用以記錄原有客戶端的IP地址和原來客戶端的請求的服務器地址。log_formataccess'$remote_addr-$remote_user[$time_local]"$request"''$status$body_bytes_sent"$http_referer"''"$http_user_agent"$http_x_forwarded_for';#定義本虛擬主機的訪問日誌access_log/usr/local/nginx/logs/host.access.logmain;access_log/usr/local/nginx/logs/host.access.404.loglog404;#對"/connect-controller"啟用反向代理location/connect-controller{proxy_passhttp://127.0.0.1:88;#請注意此處端口號不能與虛擬主機監聽的端口號一樣(也就是server監聽的端口)proxy_redirectoff;proxy_set_headerX-Real-IP$remote_addr;#後端的Web服務器可以通過X-Forwarded-For獲取用戶真實IPproxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;#以下是一些反向代理的配置,可選。proxy_set_headerHost$host;#允許客戶端請求的最大單文件字節數client_max_body_size10m;#緩衝區代理緩衝用戶端請求的最大字節數,#如果把它設置為比較大的數值,例如256k,那麼,無論使用firefox還是IE瀏覽器,來提交任意小於256k的圖片,都很正常。如果註釋該指令,使用默認的client_body_buffer_size設置,也就是操作系統頁面大小的兩倍,8k或者16k,問題就出現了。#無論使用firefox4.0還是IE8.0,提交一個比較大,200k左右的圖片,都返回500InternalServerError錯誤client_body_buffer_size128k;#表示使nginx阻止HTTP應答代碼為400或者更高的應答。proxy_intercept_errorson;#後端服務器連接的超時時間_發起握手等候響應超時時間#nginx跟後端服務器連接超時時間(代理連接超時)proxy_connect_timeout90;#後端服務器數據回傳時間(代理發送超時)#後端服務器數據回傳時間_就是在規定時間之內後端服務器必須傳完所有的數據proxy_send_timeout90;#連接成功後,後端服務器響應時間(代理接收超時)#連接成功後_等候後端服務器響應時間_其實已經進入後端的排隊之中等候處理(也可以說是後端服務器處理請求的時間)proxy_read_timeout90;#設置代理服務器(nginx)保存用戶頭信息的緩衝區大小#設置從被代理服務器讀取的第一部分應答的緩衝區大小,通常情況下這部分應答中包含一個小的應答頭,默認情況下這個值的大小為指令proxy_buffers中指定的一個緩衝區的大小,不過可以將其設置為更小proxy_buffer_size4k;#proxy_buffers緩衝區,網頁平均在32k以下的設置#設置用於讀取應答(來自被代理服務器)的緩衝區數目和大小,默認情況也為分頁大小,根據操作系統的不同可能是4k或者8kproxy_buffers432k;#高負荷下緩衝大小(proxy_buffers*2)proxy_busy_buffers_size64k;#設置在寫入proxy_temp_path時數據的大小,預防一個工作進程在傳遞文件時阻塞太長#設定緩存文件夾大小,大於這個值,將從upstream服務器傳proxy_temp_file_write_size64k;}#本地動靜分離反向代理配置#所有jsp的頁面均交由tomcat或resin處理location~.(jsp|jspx|do)?${proxy_set_headerHost$host;proxy_set_headerX-Real-IP$remote_addr;proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;proxy_passhttp://127.0.0.1:8080;}}} 

Nginx 配置實例

反向代理 Demo 1

實現效果:使用 Nginx 反向代理,訪問 test.com 直接跳轉到自己的機器 127.0.0.1:8080

①啟動一個 Tomcat,瀏覽器地址欄輸入 127.0.0.1:8080。

出現如下界面:

Nginx 的這些妙用

②通過修改本地 Host 文件(C:\\Windows\\System32\\drivers\\etc),添加127.0.0.1 www.12345.com 將 www.12345.com 映射到自己的機器 IP 上。

③配置完成之後,我們便可以通過 www.test.com:8080 訪問到第一步出現的 Tomcat 初始界面。

那麼如何只需要輸入 www.12345.com 便可以跳轉到 Tomcat 初始界面呢?便用到 Nginx 的反向代理。

④修改 nginx.conf 配置文件,增加如下配置 proxy_pass:

server{listen80;server_namelocalhost;#charsetkoi8-r;#access_loglogs/host.access.logmain;location/{proxy_passhttp://127.0.0.1:8080;}

⑤如上配置,我們監聽 80 端口,訪問域名為 www.12345.com,不加端口號時默認為 80 端口,故訪問該域名時會跳轉到 127.0.0.1:8080 路徑上。

在瀏覽器端輸入 www.12345.com 結果如下:

Nginx 的這些妙用

反向代理 Demo 2

實現效果:使用 Nginx 反向代理,根據訪問的路徑跳轉到不同端口的服務中:

  • 訪問 http://127.0.0.1/java/ 直接跳轉到 127.0.0.1:8080
  • 訪問 http://127.0.0.1/egg/ 直接跳轉到 127.0.0.1:8081

①在服務器上起兩個 Tomcat,修改其中一個端口號為 8081。

在 tomcat/webapps/ 目錄下各加兩個文件夾,並隨便寫個 HTML 頁面,我建的是 java/index.html 和 egg/index.html。

②修改 nginx.conf,在 HTTP 塊中添加 serve{}:

server{listen80;server_namelocalhost;location~/java/{proxy_passhttp://127.0.0.1:8080;}location/egg/{proxy_passhttp://127.0.0.1:8081;}}

③重啟 Nginx,驗證效果:

Nginx 的這些妙用

Nginx 配置:負載均衡

隨著互聯網信息的爆炸性增長,負載均衡(Load Balance)已經不再是一個很陌生的話題。

顧名思義,負載均衡即是將負載分攤到不同的服務單元,既保證服務的可用性,又保證響應足夠快,給用戶很好的體驗。

快速增長的訪問量和數據流量催生了各式各樣的負載均衡產品,很多專業的負載均衡硬件提供了很好的功能,但卻價格不菲。

這使得負載均衡軟件大受歡迎,Nginx 就是其中的一個,在 Linux 下有 Nginx、LVS、Haproxy 等等服務可以提供負載均衡服務。

Nginx 的負載均衡是 Proxy 模塊和 Upstream 模塊搭配實現的。Upstream模塊將會啟用一個新的配置區段,在該區段定義了一組上游服務器。

實現效果:配置負載均衡。

①同時啟動兩個 Tomcat(為了方便驗證效果,修改 Tomcat 端口號的同時,順便將 Tomcat 默認歡迎頁面 apache-tomcat-9.0.29/webapps/ROOR 目錄下的 index.jsp 修改下,看下 8081 歡迎頁的“蛋蛋”沒):

Nginx 的這些妙用

②修改 nginx.conf:

http{upstreammyserver{serverlocalhost:8080;serverlocalhost:8081;}server{listen80;location/{proxy_passhttp://myserver;}}}

③重啟 Nginx,驗證效果(默認輪詢的方式,每次打開新窗口,8080 和 8081 會交替出現,同一個窗口的話需要關閉瀏覽器緩存)。

Nginx 分配策略:

  • 輪詢(默認) 每個請求按時間順序逐一分配到不同的後端服務器,如果後端服務器 Down 掉,能自動剔除。
  • Weight 代表權重,默認為 1,權重越高被分配的客戶端越多,指定輪詢幾率,Weight 和訪問比率成正比,用於後端服務器性能不均的情況。

例如:

upstreamserver_pool{server192.168.5.21weight=10;server192.168.5.22weight=10;}

ip_hash 每個請求按訪問 IP 的 Hash 結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決 Session 的問題。

例如:

upstreamserver_pool{ip_hash;server192.168.5.21:80;server192.168.5.22:80;}

Fair(第三方) 按後端服務器的響應時間來分配請求,響應時間短的優先分配。

upstreamserver_pool{server192.168.5.21:80;server192.168.5.22:80;fair;}

Nginx 配置:動靜分離

Nginx 動靜分離簡單來說就是把動態跟靜態請求分開,不能理解成只是單純的把動態頁面和靜態頁面物理分離。

嚴格意義上說應該是動態請求跟靜態請求分開,可以理解成使用 Nginx 處理靜態頁面,Tomcat 處理動態頁面。

動靜分離從目前實現角度來講大致分為兩種:

  • 純粹把靜態文件獨立成單獨的域名,放在獨立的服務器上,也是目前主流推崇的方案;
  • 動態跟靜態文件混合在一起發佈,通過 Nginx 來分開。

通過 Location 指定不同的後綴名實現不同的請求轉發。通過 Expires 參數設置,可以使瀏覽器緩存過期時間,減少與服務器之前的請求和流量。

具體 Expires 定義:是給一個資源設定一個過期時間,也就是說無需去服務端驗證,直接通過瀏覽器自身確認是否過期即可, 所以不會產生額外的流量。

此種方法非常適合不經常變動的資源(如果經常更新的文件, 不建議使用 Expires 來緩存)。

我這裡設置 3d,表示在這 3 天之內訪問這個 URL,發送一個請求,比對服務器該文件最後更新時間沒有變化,則不會從服務器抓取,返回狀態碼 304,如果有修改,則直接從服務器重新下載,返回狀態碼 200。

Nginx 的這些妙用

①服務器找個目錄存放自己的靜態文件:

Nginx 的這些妙用

②修改 nginx.conf:

server{listen80;server_namelocalhost;location/static/{root/usr/data/www;}location/image/{root/usr/data/;autoindexon;}

③./nginx -s reload,驗證效果:

Nginx 的這些妙用

添加監聽端口、訪問名字重點是添加 Location,最後檢查 Nginx 配置是否正確即可,然後測試動靜分離是否成功,只需要刪除後端 Tomcat 服務器上的某個靜態文件,查看是否能訪問,如果可以訪問說明靜態資源 Nginx 直接返回了,不走後端 Tomcat 服務器。

Nginx 的 Rewrite

Rewrite 是 Nginx 服務器提供的一個重要的功能,它可以實現 URL 重寫和重定向功能。

場景如下:

  • URL 訪問跳轉,支持開發設計。頁面跳轉、兼容性支持(新舊版本更迭)、展示效果(網址精簡)等
  • SEO 優化(Nginx 偽靜態的支持)
  • 後臺維護、流量轉發等
  • 安全(動態界面進行偽裝)

該指令是通過正則表達式的使用來改變 URI。可以同時存在一個或多個指令。需要按照順序依次對 URL 進行匹配和處理。

該指令可以在 Server 塊或 Location 塊中配置,其基本語法結構如下:

rewriteregexreplacement[flag];

①採用反向代理 Demo2 中的例子,修改 nginx.conf(只多加了一行 Rewrite):

 
server{listen80;server_namelocalhost;location/java/{proxy_passhttp://127.0.0.1:8080;rewrite^/java/egg/redirect;}location/egg/{proxy_passhttp://127.0.0.1:8081;}}

②./nginx -s reload,驗證效果(輸入 ip/java/ 被重定向到了 egg):

Nginx 的這些妙用

Rewrite 指令可以在 Server 塊或 Location 塊中配置,其基本語法結構如下:

rewriteregexreplacement[flag];
  • rewrite 的含義:該指令是實現 URL 重寫的指令。
  • regex 的含義:用於匹配 URI 的正則表達式。
  • replacement:將 regex 正則匹配到的內容替換成 replacement。
  • flag:flag 標記。

flag 有如下值:

  • last:本條規則匹配完成後,繼續向下匹配新的 Location URI 規則。(不常用)
  • break:本條規則匹配完成即終止,不再匹配後面的任何規則(不常用)。
  • redirect:返回 302 臨時重定向,瀏覽器地址會顯示跳轉新的 URL 地址。
  • permanent:返回 301 永久重定向。瀏覽器地址會顯示跳轉新的 URL 地址。
rewrite^/(.*)http://www.360.cn/$1permanent;

Nginx 高可用

如果將 Web 服務器集群當做一個城池,那麼負載均衡服務器就相當於城門。如果“城門”關閉了,與外界的通道就斷了。

如果只有一臺 Nginx 負載服務器,當故障宕機的時候,就會導致整個網站無法訪問。

所以我們需要兩臺以上 Nginx 來實現故障轉移和高可用:

Nginx 的這些妙用

那麼如何配置高可用

①雙機熱備方案

這種方案是國內企業中最為普遍的一種高可用方案,雙機熱備其實就是指一臺服務器在提供服務,另一臺為某服務的備用狀態,當一臺服務器不可用另外一臺就會頂替上去。

Keepalived 是什麼?Keepalived 軟件起初是專為 LVS 負載均衡軟件設計的,用來管理並監控 LVS 集群系統中各個服務節點的狀態。

後來又加入了可以實現高可用的 VRRP (Virtual Router Redundancy Protocol ,虛擬路由器冗餘協議)功能。

因此,Keepalived 除了能夠管理 LVS 軟件外,還可以作為其他服務(例如:Nginx、Haproxy、MySQL 等)的高可用解決方案軟件。

②故障轉移機制

Keepalived 高可用服務之間的故障切換轉移,是通過 VRRP 來實現的。

在 Keepalived服務正常工作時,主 Master 節點會不斷地向備節點發送(多播的方式)心跳消息,用以告訴備 Backup 節點自己還活著。

當主 Master 節點發生故障時,就無法發送心跳消息,備節點也就因此無法繼續檢測到來自主 Master 節點的心跳了,於是調用自身的接管程序,接管主 Master 節點的 IP 資源及服務。

而當主 Master節點恢復時,備 Backup 節點又會釋放主節點故障時自身接管的 IP 資源及服務,恢復到原來的備用角色。

實現方法如下:

①準備兩臺安裝 Nginx 和 Keepaliver(yum install keepalived -y)的服務器

②修改兩臺服務器上的 /etc/keepalived/keepalived.conf

#主機#檢測腳本vrrp_scriptchk_http_port{script"/usr/local/src/check_nginx.sh"#心跳執行的腳本,檢測nginx是否啟動interval2#(檢測腳本執行的間隔,單位是秒)weight2#權重}#vrrp實例定義部分vrrp_instanceVI_1{stateMASTER#指定keepalived的角色,MASTER為主,BACKUP為備interfaceens33#當前進行vrrp通訊的網絡接口卡(當前centos的網卡)用ifconfig查看你具體的網卡virtual_router_id66#虛擬路由編號,主從要一直priority100#優先級,數值越大,獲取處理請求的優先級越高advert_int1#檢查間隔,默認為1s(vrrp組播週期秒數)#授權訪問authentication{auth_typePASS#設置驗證類型和密碼,MASTER和BACKUP必須使用相同的密碼才能正常通信auth_pass1111}track_script{chk_http_port#(調用檢測腳本)}virtual_ipaddress{192.168.16.150#定義虛擬ip(VIP),可多設,每行一個}}


#備機#檢測腳本vrrp_scriptchk_http_port{script"/usr/local/src/check_nginx.sh"#心跳執行的腳本,檢測nginx是否啟動interval2#(檢測腳本執行的間隔)weight2#權重}#vrrp實例定義部分vrrp_instanceVI_1{stateBACKUP#指定keepalived的角色,MASTER為主,BACKUP為備interfaceens33#當前進行vrrp通訊的網絡接口卡(當前centos的網卡)用ifconfig查看你具體的網卡virtual_router_id66#虛擬路由編號,主從要一直priority99#優先級,數值越大,獲取處理請求的優先級越高advert_int1#檢查間隔,默認為1s(vrrp組播週期秒數)#授權訪問authentication{auth_typePASS#設置驗證類型和密碼,MASTER和BACKUP必須使用相同的密碼才能正常通信auth_pass1111}track_script{chk_http_port#(調用檢測腳本)}virtual_ipaddress{192.168.16.150#定義虛擬ip(VIP),可多設,每行一個}} 

③新建檢測腳本(chmod 775 check_nginx.sh):

#!/bin/bash#檢測nginx是否啟動了A=`ps-Cnginx--no-header|wc-l`if[$A-eq0];then#如果nginx沒有啟動就啟動nginxsystemctlstartnginx#重啟nginxif[`ps-Cnginx--no-header|wc-l`-eq0];then#nginx重啟失敗,則停掉keepalived服務,進行VIP轉移killallkeepalivedfifi

④啟動 Nginx 和 Keepalived(systemctl start keepalived.service)

⑤模擬 Nginx 故障(關閉主服務器 Nginx),驗證,仍可以通過配置的虛擬 IP 訪問,OK。

Nginx 原理與優化參數配置

Nginx 默認採用多進程工作方式,Nginx 啟動後,會運行一個 Master 進程和多個 Worker 進程。

其中 Master 充當整個進程組與用戶的交互接口,同時對進程進行監護,管理 Worker 進程來實現重啟服務、平滑升級、更換日誌文件、配置文件實時生效等功能。

Worker 用來處理基本的網絡事件,Worker 之間是平等的,他們共同競爭來處理來自客戶端的請求。

Nginx 的這些妙用

master-workers 的機制的好處:

  • 可以使用 nginx-s reload 熱部署。
  • 每個 Worker 是獨立的進程,不需要加鎖,省掉了鎖帶來的開銷。採用獨立的進程,可以讓互相之間不會影響,一個進程退出後,其他進程還在工作,服務不會中斷,Master 進程則很快啟動新的 Worker 進程。


需要設置多少個 Worker?Nginx 同 Redis 類似都採用了 IO 多路複用機制,每個 Worker 都是一個獨立的進程,但每個進程裡只有一個主線程,通過異步非阻塞的方式來處理請求,即使是成千上萬個請求也不在話下。

每個 Worker 的線程可以把一個 CPU 的性能發揮到極致。所以 Worker 數和服務器的 CPU 數相等是最為適宜的。設少了會浪費 CPU,設多了會造成 CPU 頻繁切換上下文帶來的損耗。

#設置 worker 數量。worker_processes4#work 綁定 cpu(4 work 綁定 4cpu)。worker_cpu_affinity0001001001001000#work 綁定 cpu (4 work 綁定 8cpu 中的 4 個)。worker_cpu_affinity0000001000000100000010000001000

連接數 worker_connection:這個值是表示每個 Worker 進程所能建立連接的最大值。

所以,一個 Nginx 能建立的最大連接數,應該是 worker_connections*worker_processes。

當然,這裡說的是最大連接數,對於 HTTP 請 求 本 地 資 源 來 說 , 能 夠 支 持 的 最 大 並 發 數 量 是 worker_connections*worker_processes,如果是支持 http1.1 的瀏覽器每次訪問要佔兩個連接。

所以普通的靜態訪問最大併發數是:worker_connections*worker_processes /2。

而如果是 HTTP 作為反向代理來說,最大併發數量應該是 worker_connections*worker_processes/4。

因為作為反向代理服務器,每個併發會建立與客戶端的連接和與後端服務的連接,會佔用兩個連接。

Nginx 請求處理流程如下圖:

Nginx 的這些妙用

Nginx 模塊開發

由於 Nginx 的模塊化特性,所以可以支持模塊配置,也可以自定義模塊,Nginx 的模塊開發,程序員目前還不需要太深入。

Nginx 模塊分類如下圖:

Nginx 的這些妙用

Nginx配置選項,解壓 Nginx 後的配置操作示例:

./configure--prefix=/usr/local/nginx--with-http_stub_status_module--with-pcre--with-http_ssl_module 
Nginx 的這些妙用

Nginx 面試題

①Nginx 功能,你們項目中用到的 Nginx?

  • 反向代理服務器
  • 實現負載均衡
  • 做靜態資源服務器
  • 作為 HTTP Server

②Nginx 常用命令有哪些?

啟動nginx./sbin/nginx停止nginx./sbin/nginx-sstop./sbin/nginx-squit重載配置./sbin/nginx-sreload(平滑重啟)servicenginxreload重載指定配置文件./sbin/nginx-c/usr/local/nginx/conf/nginx.conf查看nginx版本./sbin/nginx-v檢查配置文件是否正確./sbin/nginx-t顯示幫助信息./sbin/nginx-h

③Nginx 常用配置?

worker_processes4;#工作進程數work_connections65535;#每個進程的併發能力error_log/data/nginx/logs/error.log;#錯誤日誌

④Nginx 是如何實現高併發的?

Nginx 採用的是多進程(單線程)&多路 IO 複用模型,異步,非阻塞。

一個主進程 Master,多個工作進程 Worker,每個工作進程可以處理多個請求 ,Master 進程主要負責收集、分發請求。

每當一個請求過來時,Master 就拉起一個 Worker 進程負責處理這個請求。同時 Master 進程也負責監控 Woker 的狀態,保證高可靠性。

在 Nginx 中的 Work 進程中,為了應對高併發場景,採取了 Reactor 模型(也就是 I/O 多路複用,NIO)。

I/O 多路複用模型:在 I/O 多路複用模型中,最重要的系統調用函數就是 Select(其他的還有 epoll 等)。

該方法能夠同時監控多個文件描述符的可讀可寫情況(每一個網絡連接其實都對應一個文件描述符),當其中的某些文件描述符可讀或者可寫時,Select 方法就會返回可讀以及可寫的文件描述符個數。

Nginx Work 進程使用 I/O 多路複用模塊同時監聽多個 FD(文件描述符),當 Accept、Read、Write 和 Close 事件產生時,操作系統就會回調 FD 綁定的事件處理器。

這時候 Work 進程再去處理相應事件,而不是阻塞在某個請求連接上等待。

這樣就可以實現一個進程同時處理多個連接。每一個 Worker 進程通過 I/O 多路複用處理多個連接請求。

為了減少進程切換(需要系統調用)的性能損耗,一般設置 Worker 進程數量和 CPU 數量一致。

⑤Nginx 和 Apache 的區別?

輕量級,同樣起 Web 服務,比 Apache 佔用更少的內存及資源抗併發,Nginx 處理請求是異步非阻塞的,而 Apache 則是阻塞型的。

在高併發下 Nginx 能保持低資源低消耗高性能高度模塊化的設計,編寫模塊相對簡單,最核心的區別在於 Apache 是同步多進程模型,一個連接對應一個進程;Nginx是異步的,多個連接(萬級別)可以對應一個進程。

⑥Nginx 的 Upstream 支持的負載均衡方式?

  • 輪詢(默認)
  • weight:指定權重
  • ip_hash:每個請求按訪問 ip 的 hash 結果分配,這樣每個訪客固定訪問一個後端服務器
  • 第三方:fair、url_hash

⑦Nginx 常見的優化配置有哪些?

  • 調整 worker_processes:指 Nginx 要生成的 Worker 數量,最佳實踐是每個 CPU 運行 1 個工作進程。
  • 最大化 worker_connections。
  • 啟用 Gzip 壓縮:壓縮文件大小,減少了客戶端 HTTP 的傳輸帶寬,因此提高了頁面加載速度。
  • 為靜態文件啟用緩存。
  • 禁用 access_logs:訪問日誌記錄,它記錄每個 Nginx 請求,因此消耗了大量 CPU 資源,從而降低了 Nginx 性能。


分享到:


相關文章: