偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

百萬并發(fā)下的Nginx優(yōu)化,看這一篇就夠了!

開發(fā) 架構(gòu) 開發(fā)工具
本文作者主要分享在 Nginx 性能方面的實踐經(jīng)驗,希望能給大家?guī)硪恍┫到y(tǒng)化思考,幫助大家更有效地去做 Nginx。

本文作者主要分享在 Nginx 性能方面的實踐經(jīng)驗,希望能給大家?guī)硪恍┫到y(tǒng)化思考,幫助大家更有效地去做 Nginx。

[[249062]]

優(yōu)化方法論

我重點(diǎn)分享如下兩個問題:

  • 保持并發(fā)連接數(shù),怎么樣做到內(nèi)存有效使用。
  • 在高并發(fā)的同時保持高吞吐量的重要要點(diǎn)。

實現(xiàn)層面主要是三方面優(yōu)化,主要聚焦在應(yīng)用、框架、內(nèi)核。

硬件限制可能有的同學(xué)也都聽過,把網(wǎng)卡調(diào)到萬兆、10G 或者 40G 是最好的,磁盤會根據(jù)成本的預(yù)算和應(yīng)用場景來選擇固態(tài)硬盤或者機(jī)械式硬盤,關(guān)注 IOPS 或者 BPS。

CPU 是我們重點(diǎn)看的一個指標(biāo)。實際上它是把操作系統(tǒng)的切換代價換到了進(jìn)程內(nèi)部,所以它從一個連接器到另外一個連接器的切換成本非常低,它性能很好,協(xié)程 Openresty 其實是一樣的。

資源的高效使用,降低內(nèi)存是對我們增大并發(fā)性有幫助的,減少 RTT、提升容量。

Reuseport 都是圍繞著提升 CPU 的機(jī)核性。還有 Fast Socket,因為我之前在阿里云的時候還做過阿里云的網(wǎng)絡(luò),所以它能夠帶來很大的性能提升,但是問題也很明顯,就是把內(nèi)核本身的那套東西繞過去了。

請求的“一生”

下面我首先會去聊一下怎么看“請求”,了解完這個以后再去看怎么優(yōu)化就會很清楚了。

說這個之前必須再說一下 Nginx 的模塊結(jié)構(gòu),像 Nginx 以外,任何一個外部框架都有個特點(diǎn),如果想形成整個生態(tài)必須允許第三方的代碼接進(jìn)來,構(gòu)成一個序列,讓一個請求挨個被模塊共同處理。

那 Nginx 也一樣,這些模塊會串成一個序列,一個請求會被挨個的處理。在核心模塊里有兩個,分別是 Steam 和 NGX。

請求到來

一個連接開始剛剛建立請求到來的時候會發(fā)生什么事情?先是操作系統(tǒng)內(nèi)核中有一個隊列,等著我們的進(jìn)程去系統(tǒng)調(diào)用,這時候因為有很多工作進(jìn)程,誰會去調(diào)用呢,這有個負(fù)載均衡策略。

現(xiàn)在有一個事件模塊,調(diào)用了 Epoll Wait 這樣的接口,Accept 建立好一個新連接,這時會分配到連接內(nèi)存池,這個內(nèi)存池不同于所有的內(nèi)存池,它在連接剛創(chuàng)建的時候會分配,什么時候會釋放呢?

只有這個連接關(guān)閉的時候才會去釋放。接下來就到了 NGX 模塊,這時候會加一個 60 秒的定時器。

就是在建立好連接以后 60 秒之內(nèi)沒有接到客戶端發(fā)來的請求就自動關(guān)閉,如果 60 秒過來之后會去分配內(nèi)存,讀緩沖區(qū)。什么意思呢?

現(xiàn)在操作系統(tǒng)內(nèi)核已經(jīng)收到這個請求了,但是我的應(yīng)用程序處理不了,因為沒有給它讀到用戶態(tài)的內(nèi)存里去,所以這時候要分配內(nèi)存。

從連接內(nèi)存池這里分配,那要分配多大呢?會擴(kuò)到 1K。

收到請求

當(dāng)收到請求以后,接收 Url 和 Header,分配請求內(nèi)存池,這時候 Request Pool Size 是 4K,大家發(fā)現(xiàn)是不是和剛才的有一個 8 倍的差距,這是因為利用態(tài)的內(nèi)存是非常消耗資源的。

再看為什么會消耗資源,首先會用狀態(tài)機(jī)解去形容,所謂狀態(tài)機(jī)解就是把它當(dāng)做一個序列,一個支節(jié)一個支節(jié)往下解,如果發(fā)現(xiàn)換行了那就是請求行解完了。

但如果這個請求特別長的時候,就會去再分配更大的,剛剛 1K 不夠用了,為什么是 4 乘 8K 呢?

就是因為當(dāng) 1K 不夠了不會一次性分配 32K,而是一次性分配 8K。如果 8K 以后還沒有解析到剛才的標(biāo)識符,就會分配第二個 8K。

我之前收到的所有東西都不會釋放,只是放一個指針,指到 Url 或者指到那個協(xié)議,標(biāo)識它有多長就可以了。

接下來解決 Header,這個流程一模一樣的沒有什么區(qū)別,這時候還會有一個不夠用的情況,當(dāng)我接收完所有的 Header 以后,會把剛剛的定時器給移除,移除后接下來做 11 個階段的處理。

也就是說剛剛所有的外部服務(wù)器都是通過很多的模塊串成在一起處理一個請求的。

像剛剛兩頁 PPT 都在說藍(lán)色的區(qū)域,那么請求接下來 11 個階段是什么意思呢?這個黃色的、綠色的,還有右邊這個都是在 11 階段之中。

這 11 個階段大家也不用記,非常簡單,只要掌握三個關(guān)鍵詞就可以。

剛剛讀完 Header 要做處理,所以這時候第一階段是 Post-Read。接下來會有 Rewrite,還有 Access 和 Preaccess。

先看左手邊,當(dāng)我們下載完 Nginx 源碼編以后會有一個 Referer,所有的第三方數(shù)據(jù)都會在這里呈現(xiàn)有序排列。

這些序列中并不是簡單的一個請求給它再給它,先是分為 11 個階段,每個階段之內(nèi)大家是有序一個個往后來的,但在 11 個階段中是按階段來的。

我把它分解一下,第一個 Referer 這階段有很多模塊,后面這是有序的。

這個圖比剛剛的圖多了兩個關(guān)鍵點(diǎn):

  • 第一到了某一個模塊可以決定繼續(xù)向這序列后的模塊執(zhí)行,也可以說直接跳到下個階段,但不能說跳多個階段。
  • 第二是生成了向客戶端反映的響應(yīng),這時候要對響應(yīng)做些處理,這里是有序的,先做縮略圖再做壓縮,所以它是有嚴(yán)格順序的。

請求的反向代理

請求的反向代理,反向代理這塊是我們 Nginx 的重點(diǎn)應(yīng)用場景,因為 Nginx 會考慮一種場景,客戶端走的是公網(wǎng),所以網(wǎng)絡(luò)環(huán)境非常差,網(wǎng)速非常慢。

如果簡單用一個緩沖區(qū)從客戶端收一點(diǎn)發(fā)給上游服務(wù)器,那上游服務(wù)器的壓力會很大,因為上游服務(wù)器往往它的效率高,所以都是一個請求被處理完之前不會再處理下一個請求。

Nginx 考慮到這個場景,它會先把整個請求全部收完以后,再向上游服務(wù)器建立連接,所以是默認(rèn)第一個配置,就是 Proxy Request Buffering On,存放包體至文件,默認(rèn) Size 是 8K。

那建立上游連接的時候會放 Time Out,60 秒,添加超時定時器,也是 60 秒的。

發(fā)出請求(讀取文體包件),如果向上游傳一個很大的包體的話,那 Sizk 就是 8K。

默認(rèn) Proxy Limit Rate 是打開的,我們會先把這個請求全部緩存到端來,所以這時候有個 8×8K,如果關(guān)掉的話,也就是從上游發(fā)一點(diǎn)就往下游發(fā)一點(diǎn)。

知道這個流程以后,再說這里的話大家可以感覺到這里的內(nèi)存消耗還是蠻大的。

返回響應(yīng)

返回響應(yīng),這里面其實內(nèi)容蠻多的,我給大家簡化一下,還是剛剛官方的那個包,這也是有順序的從下往上看,如果有大量第三方模塊進(jìn)來的話,數(shù)量會非常高。

第一個關(guān)鍵點(diǎn)是上面的 Header Filter,上面是 Write Filter,下面是 Postpone Filter,這里還有一個 Copy Filter,它又分為兩類,一類是需要處理,一類是不需要處理的。

OpenResty 的指令,第一代碼是在哪里執(zhí)行的,第二個是 SDK。

應(yīng)用層優(yōu)化

協(xié)議

做應(yīng)用層的優(yōu)化我們會先看協(xié)議層有沒有什么優(yōu)化,比如說編碼方式、Header 每次都去傳用 Nginx 的架構(gòu),以至于浪費(fèi)了很多的流量。我們可以改善 Http2,有很多這樣的協(xié)議會大幅度提升它的性能。

當(dāng)然如果你改善 Http2 了,會帶來其他的問題,比如說 Http2 必須走這條路線。

這條路線又是一個很大的話題,它涉及到安全性和性能,是互相沖突的東西。

壓縮

我們希望“商”越大越好,壓縮這里會有一個重點(diǎn)提出來的動態(tài)和靜態(tài),比如說我們用了拷貝,比如說可以從磁盤中直接由內(nèi)核來發(fā)網(wǎng)卡,但一旦做壓縮的話就不得不先把這個文件讀到 Nginx,交給后面的極內(nèi)核去做一下處理。

Keepalive 長連接也是一樣的,它也涉及到很多東西,簡單來看這也就是附用連接。

因為連接有一個慢啟動的過程,一開始它的窗口是比較小,一次可能只傳送很小的 1K 的,但后面可能會傳送幾十K,所以你每次新建連接它都會重新開始,這是很慢的。

當(dāng)然這里還涉及到一個問題,因為 Nginx 內(nèi)核它默認(rèn)打開了一個連接空閑的時候,長連接產(chǎn)生的作用也會下降。

提高內(nèi)存使用率

剛剛在說具體的請求處理過程中已經(jīng)比較詳細(xì)的把這問題說清楚了,這里再總結(jié)一下,在我看來有一個角度,Nginx 對下游只是必須要有的這些模塊,Client Header、Buffer Size:1K,上游網(wǎng)絡(luò) Http 包頭和包體。

CPU 通過緩存去取儲存上東西的時候,它是一批一批取的,每一批目前是 64 字節(jié),所以默認(rèn)的是 8K。

如果你配了 32 它會給你上升到 64;如果你配了 65 會升到 128,因為它是一個一個序列化重組的。

所以了解這個東西以后自己再配的時候就不會再犯問題。紅黑樹這里用的非常多,因為是和具體的模塊相關(guān)。

限速

大部分我們在做分公司流控的時候,主要在限什么呢?主要限 Nginx 向客戶端發(fā)送響應(yīng)的速度。

這東西非常好用,因為可以和 Nginx 定量連接在一起。這不是限上游發(fā)請求的速度,而是在限從上游接響應(yīng)的速度。

Worker 間負(fù)載均衡

當(dāng)時我在用 0.6 版本的時候那時候都在默認(rèn)用這個,這個“鎖”它是在用進(jìn)程間同步方式去實現(xiàn)負(fù)載均衡,這個負(fù)載均衡怎么實現(xiàn)呢?

就是保證所有的 Worker 進(jìn)程,同一時刻只有一個 Worker 進(jìn)程在處理距離,這里就會有好幾個問題,綠色的框代表它的吞吐量,吞吐量不高,所以會導(dǎo)致第二個問題 Requests,也是比較長的,這個方差就非常的大。

如果把這個“鎖”關(guān)掉以后,可以看到吞吐量是上升的,方差也在下降,但是它的時間在上升,為什么會出現(xiàn)這樣的情況?

因為會導(dǎo)致一個 Worker 可能會非常忙,它的連接數(shù)已經(jīng)非常高了,但是還有其他的 Worker 進(jìn)程是很閑的。

如果用了 Requests,它會在內(nèi)核層面上做負(fù)載均衡。這是一個專用場景,如果在復(fù)雜應(yīng)用場景下開 Requests 和不開是能看到明顯變化的。

超時

這里我剛剛說了好多,它是一個紅黑樹在實現(xiàn)的。唯一要說的也就是這里,Nginx 現(xiàn)在做四層的反向代理也很成熟了。

像 UTP 協(xié)議是可以做反向代理的,但要把有問題的連接迅速踢掉的話,要遵循這個原則,一個請求對一個響應(yīng)。

緩存

只要想提升性能必須要在緩存上下工夫。比如說我以前在阿里云做云盤,云盤緩存的時候就會有個概念叫空間維度緩存,在讀一塊內(nèi)容的時候可能會把這內(nèi)容周邊的其他內(nèi)容也讀到緩存中。

大家如果熟悉優(yōu)化的話也會知道有分支預(yù)測先把代碼讀到那空間中,這個用的比較少,基于時間維度用的比較多了。

減少磁盤 IO

其實要做的事也非常多,優(yōu)化讀取,Sendfile 零拷貝、內(nèi)存盤、SSD 盤。減少寫入,AIO,磁盤是遠(yuǎn)大于內(nèi)存的,當(dāng)它把你內(nèi)存消化完的時候還會退化成一個調(diào)用。

像 Thread Pool 只用讀文件,當(dāng)退化成這種模式變多線程可以防止它的主進(jìn)程被阻塞住,這時候官方的博客上說是有 9 倍的性能提升。

系統(tǒng)優(yōu)化

提升容量配置

我們建連接的時候也有,還有些向客戶端發(fā)起連接的時候會有一個端口范圍,還有一些像對于網(wǎng)卡設(shè)備的。

CPU緩存的親和性

CPU緩存的親和性,這看情況了,現(xiàn)在用 L3 緩存差不多也 20 兆的規(guī)模,CPU 緩存的親和性是一個非常大的話題,這里就不再展開了。

NUMA 架構(gòu)的 CPU 親和性

把內(nèi)存分成兩部分,一部分是靠近這個核,一部分靠近那個核,如果訪問本核的話就會很快,靠近另一邊大概會耗費(fèi)三倍的損耗。對于多核 CPU 的使用對性能提升很大的話就不要在意這個事情。

網(wǎng)絡(luò)快速容錯

因為 TCP 的連接最麻煩的是在建立連接和關(guān)閉連接,這里有很多參數(shù)都是在調(diào),每個地方重發(fā),多長時間重發(fā),重發(fā)多少次。

這里給大家展示的是快啟動,有好幾個概念在里面,第一個概念在快速啟動的時候是以兩倍的速度。

因為網(wǎng)的帶寬是有限的,當(dāng)你超出網(wǎng)絡(luò)帶寬的時候其中的網(wǎng)絡(luò)設(shè)備是會被丟包的,也就是控制量在往下降,那再恢復(fù)就會比較慢。

TCP 協(xié)議優(yōu)化

TCP 協(xié)議優(yōu)化,本來可能差不多要四個來回才能達(dá)到每次的傳輸在網(wǎng)絡(luò)中有幾十 K,那么提前配好的話用增大初始窗口讓它一開始就達(dá)到最大流量。

提高資源效率

提高資源效率,這一頁東西就挺多了,比如說先從 CPU 看,TCP Defer Accept,如果有這個的話,實際上會犧牲一些即時性,但帶來的好處是第一次建立好連接沒有內(nèi)容過來的時候是不會激活 Nginx 做切換的。

內(nèi)存在說的時候是系統(tǒng)態(tài)的內(nèi)存,在內(nèi)存大和小的時候操作系統(tǒng)做了一次優(yōu)化,在壓力模式和非壓力模式下為每一個連接分配的系統(tǒng)內(nèi)存可以動態(tài)調(diào)整。

網(wǎng)絡(luò)設(shè)備的核心只解決一個問題,變單個處理為批量處理,批量處理后吞吐量一定是會上升的。

因為消耗的資源變少了,切換次數(shù)變少了,它們的邏輯是一樣的,就這些邏輯和我一直在說的邏輯都是同一個邏輯,只是應(yīng)用在不同層面會產(chǎn)生不同的效果。

端口復(fù)用,像 Reals 是很好用的,因為它可以把端口用在上游服務(wù)連接的層面上,沒有帶來隱患。

提升多 CPU 使用效率

提升多 CPU 使用效率,上面很多東西都說到了,重點(diǎn)就兩個,一是 CPU 綁定,綁定以后緩存更有效。多隊列網(wǎng)卡,從硬件層面上已經(jīng)能夠做到了。

BDP,帶寬肯定是知道的,帶寬和時延就決定了帶寬時延積,那吞吐量等于窗口或者時延。

內(nèi)存分配速度也是我們關(guān)注的重點(diǎn),當(dāng)并發(fā)量很大的時候內(nèi)存的分配是比較糟糕的,大家可以看到有很多它的競品。

PCRE 的優(yōu)化,這用最新的版本就好。

作者:陶輝

介紹:曾在華為、騰訊公司做底層數(shù)據(jù)相關(guān)的工作,寫過一本書叫《深入理解 Nginx:模塊開發(fā)與架構(gòu)解析》,目前在杭州智鏈達(dá)作為聯(lián)合創(chuàng)始人擔(dān)任技術(shù)總監(jiān)一職,目前專注于使用互聯(lián)網(wǎng)技術(shù)助力建筑行業(yè)實現(xiàn)轉(zhuǎn)型升級。 

 

責(zé)任編輯:武曉燕 來源: 高效運(yùn)維
相關(guān)推薦

2022-08-01 11:33:09

用戶分析標(biāo)簽策略

2021-04-08 07:37:39

隊列數(shù)據(jù)結(jié)構(gòu)算法

2023-09-11 08:13:03

分布式跟蹤工具

2020-02-18 16:20:03

Redis ANSI C語言日志型

2023-02-10 09:04:27

2022-06-20 09:01:23

Git插件項目

2017-03-11 22:19:09

深度學(xué)習(xí)

2022-04-07 10:39:21

反射Java安全

2023-11-18 09:30:42

模型AI

2020-07-03 08:21:57

Java集合框架

2019-05-14 09:31:16

架構(gòu)整潔軟件編程范式

2023-10-17 08:15:28

API前后端分離

2018-05-22 08:24:50

PythonPyMongoMongoDB

2024-09-23 08:00:00

消息隊列MQ分布式系統(tǒng)

2020-09-22 17:31:13

運(yùn)維架構(gòu)技術(shù)

2019-04-02 10:51:29

瀏覽器緩存前端

2017-03-13 09:50:46

Python裝飾器

2019-12-31 09:56:16

Linux 系統(tǒng) 數(shù)據(jù)

2019-09-05 08:14:44

Puppet部署結(jié)構(gòu)

2020-07-06 08:06:00

Java模塊系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號