本文我們聊一下關(guān)于Nginx配置優(yōu)化的內(nèi)容邓线,相信對(duì)于Nginx你一定并不陌生淌友,它是一款輕量級(jí)的開源Web服務(wù)及代理程序。在Nginx出現(xiàn)之前市場(chǎng)上主流兩款Web服務(wù)骇陈,一款是Windows系統(tǒng)上的IIS震庭,另外一款是Linux系統(tǒng)上的Apache。而在Nginx誕生后你雌,因其輕量化器联、支持高并發(fā)等特性,逐漸蠶食了這兩款Web服務(wù)的市場(chǎng)份額。目前國(guó)內(nèi)大量企業(yè)早已廣泛的使用 Nginx拨拓。既然 Nginx 使用這么廣泛肴颊,那么我們?cè)谶\(yùn)維工作中如何對(duì)其進(jìn)行優(yōu)化和配置便成了重中之重。
你在閱讀本文之前千元,我們需要提前掌握一些基礎(chǔ)知識(shí)苫昌,包括:
熟悉Linux 的基礎(chǔ)操作;
了解 Nginx 安裝和基礎(chǔ)配置幸海;
對(duì) HTTP 請(qǐng)求過程有一定了解祟身。
Nginx 的優(yōu)化主要分為兩部分,一部分是基礎(chǔ)配置優(yōu)化物独,另外一部分是緩存配置優(yōu)化袜硫。
基礎(chǔ)配置優(yōu)化主要包括:
- CPU親和性優(yōu)化;
- Nginx 模型優(yōu)化挡篓;
- Nginx 傳輸方式優(yōu)化婉陷;
- Nginx 文件壓縮優(yōu)化。
緩存配置優(yōu)化主要包括:
- 瀏覽器緩存優(yōu)化
- 代理緩存優(yōu)化
- HTTPS SSL 緩存優(yōu)化
- KV 服務(wù)緩存優(yōu)化
基礎(chǔ)配置優(yōu)化
CPU 親和性
所謂的 CPU 親和性是做什么的呢官研?現(xiàn)在的CPU通常是多核的秽澳,并可以通過超線程來虛擬更多核數(shù) ,那親和力就是為多核 CPU 需做到讓 Nginx 服務(wù)充分的配合使用戏羽,從而提高性能担神。 Nginx運(yùn)行時(shí)會(huì)啟用 1 個(gè) master 進(jìn)程及多個(gè) worker 進(jìn)程,worker 進(jìn)程負(fù)責(zé)處理請(qǐng)求始花,如果 worker 進(jìn)程在多核 CPU中發(fā)生頻繁的調(diào)度就會(huì)損耗性能妄讯。在這種情況下,我們希望減少這種頻繁調(diào)度酷宵,讓每一個(gè) Nginx 的worker 線程都能夠固定到具體的 CPU核心上亥贸,所以就需要配置 Nginx 的 CPU 親和性來解決這個(gè)問題。
由于 Nginx CPU親和性配置本身有多套配置方案浇垦,這里推薦你直接將配置項(xiàng)設(shè)置成auto(worker_cpu_affinity)炕置,即采用了 Nginx 推薦的 CPU 綁核策略方式。另外的一個(gè)方式是手動(dòng)綁定男韧,將 worker 線程數(shù)量與 CPU 核心數(shù)一一綁定方式設(shè)置朴摊。我們?cè)O(shè)置成auto Nginx 會(huì)自動(dòng)識(shí)別并按照推薦策略來分配worker 線程和 CPU。
如圖所示煌抒,我們看到 CPU 的核心有 8 個(gè)仍劈,即CPU0~CPU7厕倍,如果我們?cè)O(shè)置成 auto 后寡壮,那么Nginx會(huì)將 8 個(gè) worker 線程一對(duì)一地按照推薦策略綁定到 CPU 核心上,這樣避免 CPU 頻繁對(duì) worker 線程進(jìn)行調(diào)度,從而降低 CPU 損耗况既。
IO 流事件模型
我們經(jīng)痴饨Γ可以在 Nginx 下面看到的 events 配置模塊中默認(rèn)設(shè)置了 use epoll,表示 Nginx 使用 epoll 這個(gè) IO 流事件模型棒仍,那為什么Nginx 會(huì)選擇使用 epoll 呢悲靴?這是因?yàn)?epoll有以下這些得天獨(dú)厚的優(yōu)勢(shì)。
首先莫其,Linux 系統(tǒng)下一切皆文件癞尚,比如我們打開一個(gè)設(shè)備,它便會(huì)產(chǎn)生一個(gè)文件描述符乱陡。在產(chǎn)生一個(gè)進(jìn)程時(shí)浇揩,這個(gè)進(jìn)程便需要一個(gè)進(jìn)程描述符,這個(gè)進(jìn)程描述符也是一個(gè)文件憨颠。所以在 Nginx 處理請(qǐng)求的時(shí)候胳徽,每一個(gè)請(qǐng)求都會(huì)產(chǎn)生處理請(qǐng)求的描述符。
其次爽彤,在 Nginx 處理大規(guī)模請(qǐng)求的時(shí)候养盗,為了提高并發(fā)效率需要采用異步非阻塞模型,這又和 epoll有什么關(guān)系呢适篙?epoll 本身是以異步非阻塞模型來處理請(qǐng)求流中的事件流往核。
這里還需要注意一點(diǎn),并不是所有的 Linux 操作系統(tǒng)都可以使用epoll匙瘪,它是在 kernel 2.6 版本以后提出的铆铆,早期內(nèi)核使用的 select\poll 模型,select 模型比 epoll 模型性能要低很多丹喻,有經(jīng)驗(yàn)的運(yùn)維同學(xué)一定深有體會(huì)薄货。
通過上面的背景鋪墊,我們?cè)賮碓敿?xì)介紹下epoll 相比于 select 模型具備的優(yōu)勢(shì):
- epoll 處理事件流模型是線程安全的碍论;
- epoll 跟 select 模型相比調(diào)用 fd 文件描述符時(shí)使用了 mmap 共享用戶和內(nèi)核的部分空間谅猾,提高了效率;
- epoll 是基于事件驅(qū)動(dòng)的鳍悠,相比 select 需要掃描整個(gè)文件描述符的相關(guān)狀態(tài)税娜,epoll 基于事件驅(qū)動(dòng)避免頻繁掃描文件描述符,可以直接調(diào)用callback 回調(diào)函數(shù)藏研,效率更高敬矩;
- 取消了select模型里面單個(gè)進(jìn)程能夠監(jiān)視的文件描述符的數(shù)量存在的最大限制(1024),如果你有使用過早期的Apache版本的蠢挡,它使用的select模型弧岳,當(dāng)請(qǐng)求超過1000以后就會(huì)出現(xiàn)延遲或者請(qǐng)求錯(cuò)誤凳忙,而改用 Nginx 的話性能會(huì)得到明顯的改善。
另外補(bǔ)充下禽炬,在 events{} 配置中還涉及一個(gè)優(yōu)化的地方就是 worker_connections涧卵,這個(gè)也是在events 里面來進(jìn)行設(shè)置的,通過上面的學(xué)習(xí)我們知道了 worker 線程作用腹尖,那每一個(gè) work線程所支持的連接是有限的柳恐,這里會(huì)默認(rèn)設(shè)置成 1024,而我們?cè)谔幚砀卟l(fā)的場(chǎng)景時(shí)热幔,單個(gè) worker 線程設(shè)置成 1024 的話往往偏低澈驼,這里建議你將worker_connections 調(diào)大一些驹愚,你可以參考實(shí)際業(yè)務(wù)所需 Nginx 處理最大峰值來調(diào)大這個(gè)設(shè)置值凤优。
零拷貝
第三個(gè)基礎(chǔ)配置優(yōu)化是零拷貝报腔,所謂零拷貝的配置是在 Nginx 中的 HTTP 配置模塊中添加一個(gè)sendfile on 配置項(xiàng),它便是一個(gè)零拷貝认烁,所謂零拷貝并不代表不拷貝了肿男,而是說它做到了文件的內(nèi)核態(tài)到用戶態(tài)的零拷貝。
如圖所示却嗡,我們先來看下沒有零拷貝時(shí)文件傳輸是什么樣子的舶沛?首先 Nginx 在處理文件時(shí),會(huì)將文件傳入操作系統(tǒng)內(nèi)核態(tài)的 Buffer Cache窗价,然后傳遞到操作系統(tǒng)上層的用戶態(tài)如庭,經(jīng)用戶態(tài)的 Buffer
Cache 再傳回內(nèi)核態(tài)中,最后通過 Socket 將文件轉(zhuǎn)發(fā)出去撼港。
這個(gè)時(shí)候你會(huì)發(fā)現(xiàn)一個(gè)問題坪它,對(duì)于靜態(tài)文件并不需要流轉(zhuǎn)到用戶態(tài)中,直接通過內(nèi)核態(tài)效率更高帝牡,所以這時(shí)我們就需要在 Nginx 中開啟 sendfile on往毡,這樣靜態(tài)文件就可以通過紅色的路徑在內(nèi)核態(tài)中完成轉(zhuǎn)發(fā),而不用再去繞道用戶態(tài)靶溜,提高了效率开瞭。
文件壓縮
我們希望做到 Nginx 服務(wù)端往客戶端發(fā)送的數(shù)據(jù)越小,占用的延遲越低用戶體驗(yàn)便會(huì)越好罩息。所以往往在代理或 Nginx 中會(huì)設(shè)置文件壓縮嗤详,我們主要通過gzip 方式進(jìn)行設(shè)置,主要的設(shè)置項(xiàng)如下:
- gzip on 負(fù)責(zé)打開后端的壓縮功能瓷炮;
- gzip_buffer 16 8k 表示設(shè)置 Nginx 在處理文件壓縮時(shí)的內(nèi)存空間葱色;
- gzip_comp_level 6 表示 Nginx 在處理壓縮時(shí)的壓縮等級(jí),通常等級(jí)越高它的壓縮比就越大,但并不是說壓縮比越大越好娘香,還是需要根據(jù)實(shí)際情況來選擇合適的壓縮比苍狰,壓縮比太大影響性能恐锣,壓縮比太小起不到應(yīng)有的效果,一般來說推薦你設(shè)置成 6 就比較合適舞痰;
- gzip_http_version 1.1 表示只對(duì) HTTP 1.1 版本的協(xié)議進(jìn)行壓縮;
- gzip_proxied any 代表 Nginx 作為反向代理時(shí)依據(jù)后端服務(wù)器時(shí)返回信息設(shè)置一些 gzip 壓縮策略诀姚;
- gzip_vary on 表示是否發(fā)送Vary:Accept_Encoding 響應(yīng)頭字段响牛,實(shí)現(xiàn)通知接收方服務(wù)端作了gzip 壓縮;
- application/vnd.ms-fontobject image/x-icon; gip 壓縮類型赫段;
- gzip_disable “msie6”; 關(guān)閉 IE6 的壓縮呀打。
最后這兩項(xiàng)表示設(shè)置 zip 的壓縮類型及是否關(guān)閉客戶端使用 IE6 瀏覽器請(qǐng)求過來的壓縮,以上就是對(duì)文件壓縮的典型配置糯笙,你可以根據(jù)具體情況做一些細(xì)節(jié)上的調(diào)整贬丛。
緩存配置優(yōu)化
緩存優(yōu)化
我們先講解緩存優(yōu)化配置,基于緩存元素存放的位置给涕,再對(duì)我們所需要講的緩存作一個(gè)分類豺憔。
如果緩存的元素在客戶端的,那么主要有瀏覽器緩存和 HTTPS 緩存够庙,你可別認(rèn)為緩存文件是在客戶端恭应,這兩部分緩存效果都可以 Nginx 這種代理來進(jìn)行設(shè)置并作主要優(yōu)化。
另外一個(gè)種類代理端的緩存(也就是緩存文件存放在代理服務(wù)的節(jié)點(diǎn)中)耘眨,那Nginx 作為反向代理服務(wù)的時(shí)候昼榛,可以支持代理緩存設(shè)置。
最后一個(gè)種類是將緩存文件放入后臺(tái)服務(wù)(通過后臺(tái)服務(wù)中程序邏輯來實(shí)現(xiàn)),例如我們可以將一部分?jǐn)?shù)據(jù)通過此方式緩存剔难,比如將用戶最長(zhǎng)查看的數(shù)據(jù)(網(wǎng)站中登錄狀態(tài)胆屿、連接數(shù)等)緩存到Memcache、Redis 中偶宫,避免直接請(qǐng)求關(guān)系型數(shù)據(jù)庫或其他服務(wù)非迹,因?yàn)樾в眯矢咚钥梢越档秃蠖说难舆t,也減少請(qǐng)求對(duì)數(shù)據(jù)庫的依賴度纯趋,從而整個(gè)網(wǎng)站的性能也會(huì)有很大的提升彻秆。
只考慮緩存最優(yōu)的話,我有三點(diǎn)經(jīng)驗(yàn)可以分享給你:
- 緩存越靠前越好结闸,通常情況下整個(gè)網(wǎng)站的元素內(nèi)容越靠前越好唇兑,也就是說能放在客戶端的就放在客戶端,而不要放到后端去頻繁請(qǐng)求桦锄。
- 緩存的數(shù)據(jù)越多越好扎附,也就是能在本層級(jí)緩存的數(shù)據(jù)越多,就越可以減少對(duì)后端的請(qǐng)求结耀。
- 緩存的命中率越高越好留夜,如果設(shè)置了很多緩存匙铡,但命中率不高,同樣還是會(huì)造成穿透到后端訪問碍粥,此時(shí)還需要考慮將緩存的命中率設(shè)置的越高鳖眼,這時(shí)觀察指標(biāo),會(huì)發(fā)現(xiàn)緩存效果越優(yōu)嚼摩。
通常而言钦讳,一個(gè)網(wǎng)站如果做了緩存優(yōu)化可以比沒做緩存優(yōu)化的性能提升幾倍以上。
瀏覽器緩存
第一個(gè)就是瀏覽器緩存枕面,瀏覽器緩存通常是緩存到客戶端(如:瀏覽器愿卒、客戶端app),這就是瀏覽器緩存潮秘。
對(duì)于瀏覽器這部分緩存數(shù)據(jù)琼开,我們通常可以把靜態(tài)元素枕荞,比如用戶請(qǐng)求的圖片柜候、CSS 、JS 等元素緩存到客戶端躏精。這種緩存可以通過 Nginx配置中的expires 配置項(xiàng)進(jìn)行設(shè)置改橘,expires 后面可以加具體的時(shí)間,也可以加對(duì)應(yīng)的特定意義的數(shù)值玉控,比如 -1 表示永久緩存飞主,max 設(shè)置最大周期緩存(默認(rèn)緩存周期為 10 年),需要做具體的時(shí)間的設(shè)置可以寫入具體的時(shí)間周期高诺,比如一個(gè)小時(shí)或是一天碌识。
HTTPS 配置優(yōu)化
當(dāng)前我們很多網(wǎng)站通常在開啟HTTPS ,當(dāng)開啟https后客戶端訪問服務(wù)端打開一次瀏覽器虱而,通過https方式會(huì)比 HTTP 請(qǐng)求握手會(huì)要增加很多次從而延遲也增加了筏餐。這時(shí)就需要考慮 HTTPS 是否有更好的優(yōu)化方案來減少客戶端和服務(wù)端請(qǐng)求。
如圖中是一個(gè)https請(qǐng)求過程牡拇,實(shí)際在進(jìn)行HTTPS 請(qǐng)求之前的需要進(jìn)行TCP 的三次握手過程魁瞪,而這里我只是描述 HTTPS 的建連過程,客戶端發(fā)送hello 報(bào)文惠呼,服務(wù)端發(fā)送證書导俘,客戶端進(jìn)行加密,服務(wù)端驗(yàn)證加密剔蹋。這時(shí)開始進(jìn)行服務(wù)端與客戶端的傳輸旅薄。我們看到整個(gè) HTTPS 建連增加了部分的證書加密的協(xié)商。
多次的連接對(duì)于用戶及服務(wù)端而言泣崩,性能和延遲都會(huì)增加很多少梁。并且如果每一次瀏覽器跟服務(wù)端斷開連接以后洛口,又要進(jìn)行一次整體的建立連接的過程。為了減少客戶端和服務(wù)端的斷開重連過程凯沪,這時(shí)就需要在Nginx中配置ssl_session_cache 發(fā)揮作用第焰。
下面我們來說下這個(gè)配置原理,當(dāng)瀏覽器跟服務(wù)端建立第一次加密證書驗(yàn)證的會(huì)話后妨马,服務(wù)端會(huì)給客戶端瀏覽器緩存一個(gè) SessionKey挺举,如果客戶端跟服務(wù)端再次斷開連接,這時(shí)瀏覽器就可以拿SessionKey 直接跟服務(wù)端進(jìn)行交互身笤。只需要進(jìn)行一次校驗(yàn),就可以開始數(shù)據(jù)傳輸葵陵。我們看到有了SessionKey 這種方式后液荸,就可以避免瀏覽器跟服務(wù)端頻繁的進(jìn)行 HTTPS 會(huì)話的建聯(lián)。
通過在 Nginx 中添加 ssl_session_cache 配置脱篙,配置中分配 Nginx 在處理 SSL 會(huì)話所需要開辟的共享內(nèi)存的空間娇钱,我這里這里設(shè)置值為 10 MB,第二個(gè)參數(shù)就是設(shè)置 SSL SessionKey 的超時(shí)時(shí)間绊困,這里設(shè)置的為 10 分鐘文搂,也就是每隔 10 分鐘需要重新再進(jìn)行一次建聯(lián),這是一個(gè)在服務(wù)端的超時(shí)時(shí)間秤朗。
打開文件緩存
打開文件緩存設(shè)置在 Nginx 端煤蹭,通常而言我們會(huì)把一些靜態(tài)元素(如:JPG、CSS取视、GS)在代理端通過這種方式進(jìn)行設(shè)置硝皂,這里 Nginx 緩存的是靜態(tài)元素的元數(shù)據(jù)。那么把元數(shù)據(jù)緩存到 Nginx 端有什么好處作谭?元數(shù)據(jù)的作用就是緩存打開用戶所請(qǐng)求的靜態(tài)元素的文件路徑等信息稽物,那么如果在本地頻繁地查找之前請(qǐng)求過的靜態(tài)元素文件而沒有緩存元數(shù)據(jù)時(shí)效率比較低,而如果我們把一部分索引數(shù)據(jù)緩存到Nginx 的 Cache 下折欠,這種頻繁訪問就可以很大地提高訪問效率贝或。
我們來看 open_file_cache 具體的設(shè)置策略,max 表示最大能夠緩存的文件個(gè)數(shù)锐秦,inactive 表示最少的用戶使用次數(shù)咪奖。我們結(jié)合看一下,這個(gè)表示在 20 秒內(nèi)最小需要使用兩次酱床。如果沒有使用的話赡艰,就會(huì)把元數(shù)據(jù)刪掉,也這就是一個(gè)淘汰元數(shù)據(jù)的策略斤葱。
open_file_cache_valid 是設(shè)置主動(dòng)更新和檢查的時(shí)間慷垮,表示每隔 30 秒檢查緩存文件的元信息有沒有對(duì)應(yīng)的更新揖闸,如果有更新就需要去做對(duì)應(yīng)的更新,它是一個(gè)更新的策略料身。
代理緩存優(yōu)化
代理緩存比較常見汤纸,比如說代理 訪問PHP 后臺(tái)服務(wù)并作緩存,也可以代理 JAVA 服務(wù)芹血,緩存 JAVA后臺(tái)服務(wù)的返回?cái)?shù)據(jù)贮泞,注意這里不局限于通過 http_proxy來作代理緩存,只要 Nginx 支持的代理模式(UWSGI幔烛、SGI)都可以設(shè)置代理緩存啃擦。你可以來看一下通過http_proxy設(shè)置的如下示例:
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
location / {
proxy_cache my_cache;
…
}
proxy_cache_path 表示在本地分配哪個(gè)路徑來存儲(chǔ)并緩存后臺(tái)返回?cái)?shù)據(jù);cache levels 表示存放文件的分層方式饿悬;my_cache:10m max_size=10g 分別表示是開辟一個(gè)名為my_cache共享塊(用于統(tǒng)計(jì)訪問次數(shù))及緩存的單個(gè)文件的最大大小等令蛉。
這些都是做對(duì)應(yīng)的緩存在本地的文件目錄相關(guān)屬性的一些設(shè)置。另外一塊的設(shè)置表示在proxy_cache 的時(shí)候狡恬,通過 location 引用到cache 的名稱珠叔。
代理緩存的特性是什么呢?首先通過 Nginx 作代理弟劲,可以支持實(shí)現(xiàn)動(dòng)靜態(tài)的分離祷安,靜態(tài)元素直接交給Nginx 來處理,再把后端動(dòng)態(tài)數(shù)據(jù)適當(dāng)作緩存兔乞。通常做這種代理+緩存的架構(gòu)汇鞭,是能有效的提高整體網(wǎng)站的訪問并發(fā)性能。
對(duì)于我們提到的服務(wù)端的緩存優(yōu)化大多交給開發(fā)來做 這里就不再做非 Nginx 的緩存配置的講解了庸追。
緩存使用注意問題
對(duì)于緩存的整體使用虱咧,之前說的緩存越多越好,越靠前越好锚国,命中率越高越好腕巡,但是同時(shí)我們也需要綜合考慮,并且注意緩存在使用時(shí)遇到的一些實(shí)際問題血筑。
- 文件更新策略問題绘沉。文件后端做緩存的配置策略的時(shí)候,要考慮到緩存的刪除策略豺总、更新策略车伞。怎么保證它的后端數(shù)據(jù)更新對(duì)于前端用戶能夠及時(shí)的感知。
- 緩存命中率失敗給后端造成的瞬間壓力喻喳。我們知道另玖,當(dāng)前端緩存的元素越多,命中率越高,對(duì)于后臺(tái)的壓力就越少谦去。當(dāng)一旦前段的緩存失效慷丽,或者某個(gè)節(jié)點(diǎn)遷移,或者某一部分的前端頭信息失效鳄哭,造成后端緩存瞬間壓力要糊,就可能會(huì)造成比較災(zāi)難性的后果。所以你在網(wǎng)站設(shè)計(jì)的時(shí)候也需要考慮妆丘,怎么去避免這種緩存失效锄俄?一旦前端緩存失效,你怎么保證后端服務(wù)的高可用而不受影響勺拣?
- 多節(jié)點(diǎn)緩存一致性奶赠。你在做緩存設(shè)置的時(shí)候也需要考慮到,假設(shè)前端有很多個(gè)節(jié)點(diǎn)药有,保存同樣的一部分內(nèi)容的時(shí)候毅戈,怎么保證這些數(shù)據(jù)是能夠達(dá)到一致性,這個(gè)時(shí)候也涉及緩存架構(gòu)的設(shè)計(jì)塑猖,前端的緩存節(jié)點(diǎn)的更新策略竹祷,這些也是你在實(shí)際使用緩存時(shí)應(yīng)該注意的問題谈跛。
未完待續(xù)
文章優(yōu)先發(fā)于公眾號(hào)運(yùn)維大師兄羊苟,回復(fù)資料,更有java感憾,python蜡励,go,前端等最新視頻教程阻桅,等你來拿凉倚!
本文禁止轉(zhuǎn)載