記一次LNMP優(yōu)化過(guò)程

首先要給大家說(shuō)明以下幾點(diǎn):

1.篇幅和時(shí)間有限,本篇著重講實(shí)戰(zhàn),理論部分交給超鏈接

2.本人水平有限,希望大家不吝賜教

3.現(xiàn)在是一個(gè)CPU過(guò)剩的時(shí)代,或者說(shuō)是一個(gè)非常強(qiáng)悍的CPU帶著它坑逼的隊(duì)友們(io總線,內(nèi)存,緩存,硬盤,Linux,多進(jìn)程模型,腳本語(yǔ)言,網(wǎng)絡(luò)帶寬)去超神

4.默認(rèn)情況下使用的是2核/4G ECS

開始著手優(yōu)化之前我就明顯感覺到這個(gè)問題稍稍的超出了我的能力范圍,但是沒關(guān)系啊,先看看大家是怎么做的。

我要處理的問題有個(gè)非常洋氣的名字c10k,c10k實(shí)際上瓶頸往往出在io和內(nèi)文切換,參考。epoll很熟悉嘛,nginx已經(jīng)做好了,咱也甭操心了。協(xié)程也甭考慮了,有本事你把fpm的代碼用協(xié)程給重構(gòu)了。那問題就簡(jiǎn)單多了,優(yōu)化io就成為了。

0.優(yōu)化前奏

在優(yōu)化之前務(wù)必開啟以下日志:

1.nginx access.log?error.log

2.php error.log

3.fpm error.log?slow.log

開始優(yōu)化之前用ab壓力測(cè)試發(fā)現(xiàn)rps很低,這時(shí)候nginx輸出日志提示連接數(shù)過(guò)多。參考基友的文章(這貨錢多、活好、風(fēng)騷男同志趕緊加他)做了比較基礎(chǔ)的優(yōu)化后nginx處理能力小幅上升。這時(shí)候rps依舊不是很樂觀:46。敲個(gè)top命令看了下cpu才占用64%?。?!為啥cpu跑不滿就就到瓶頸了???這個(gè)問題很詭異啊——那是因?yàn)槟悴欢甽inux(top命令詳解)。刷新了我的三觀,us不是used,而是user的意思。是user占用cpu64%的時(shí)間片。id是0也就是說(shuō)cpu已經(jīng)跑滿了。讓人感覺不可思議的是si占用了9%左右,sy占用了27%左右。

這讓人感覺很不爽啊,就像是辛辛苦苦干了一個(gè)月36%的薪水都不屬于自己的!

si:軟中斷占用百分比

sy:內(nèi)核空間占用CPU百分比

很明顯嘛,內(nèi)文切換。這個(gè)要優(yōu)化fpm模型咱就暫時(shí)不討論了,如果你真想在這方面優(yōu)化,繼續(xù)往下看,下面討論。

1.優(yōu)化io&將mysql獨(dú)立出去


很明顯嘛,內(nèi)文切換。這個(gè)要優(yōu)化fpm模型咱就暫時(shí)不討論了,如果你真想在這方面優(yōu)化,繼續(xù)往下看,下

實(shí)際上我沒有做特殊的io優(yōu)化,沒達(dá)到那個(gè)量級(jí)嘛!我們公司現(xiàn)在的并發(fā)能達(dá)到1k足以。然后我就開了臺(tái)io優(yōu)化過(guò)的ecs+ssd。然后把mysql獨(dú)立出去使用RDS+讀寫分離。然后rps就上升到468左右了,注意哦!還沒加負(fù)載均衡。給我馬哥燒柱香吧。

個(gè)人建議如果條件允許不要自己搭mysql讀寫分離,水很深,你買阿里云RDS的錢遠(yuǎn)遠(yuǎn)少于你請(qǐng)一個(gè)高級(jí)php的錢。下面我著重講解一下為啥我非要用io優(yōu)化+ssd。這就要看你對(duì)computer?science有多深入的了解了。感謝我大學(xué)在cs上打下了不錯(cuò)的基礎(chǔ),然后去翻linux內(nèi)核的書的時(shí)候讓我可以輕松點(diǎn)進(jìn)入狀態(tài)。

2.扯點(diǎn)Linux內(nèi)核

1.首先你需要了解的是虛存
這是個(gè)很扯的問題呀,每個(gè)進(jìn)程都有4G的內(nèi)存空間去存對(duì)象、變量和數(shù)據(jù)之類的。而且是放在硬盤上。讓人感覺更扯是內(nèi)存不直接參與運(yùn)算,直接參與運(yùn)算的只有寄存器。cpu總要把數(shù)據(jù)拉倒寄存器里把,總待有個(gè)橋之類的東西實(shí)現(xiàn)這個(gè)功能吧——這個(gè)東西叫io總線

2.io總線。有限的時(shí)間我只查到了IBM PowerPC的cpu一共只有65536個(gè)8bit的io總線。現(xiàn)在你終于知道nginx 的worker_rlimit_nofile 為啥要設(shè)置65535了吧,我猜測(cè)要留一個(gè)給系統(tǒng)中斷用。這也是為啥linux的最大文件打開數(shù)是65535。

千軍萬(wàn)馬過(guò)65536個(gè)獨(dú)木橋。

這也是為啥會(huì)有層出不窮的io復(fù)用模型的出現(xiàn)。

其實(shí)后面兜了不少圈性能提升不明顯。由于公司使用的是一個(gè)非常蛋疼的框架,微擎(簡(jiǎn)稱we7)。多次給高層建議重構(gòu)無(wú)果,最終只能硬著頭皮優(yōu)化了。在這里順便提醒大家一句:千萬(wàn)不要不要以為php簡(jiǎn)單就動(dòng)不動(dòng)自己動(dòng)手寫個(gè)框架,因?yàn)槟愫茈y有機(jī)會(huì)像開源框架一樣接受市場(chǎng)的考驗(yàn),你更難有開源社區(qū)那么多有熱情的志愿者不斷貢獻(xiàn)代碼去迭代。

我簡(jiǎn)單拿we7和tp5對(duì)比了一下。發(fā)現(xiàn)tp5在優(yōu)化完nginx cgi連接超時(shí)以后表現(xiàn)的很穩(wěn)定ab測(cè)試下幾乎不會(huì)有Failed。但是we7只要超過(guò)1000的用戶并發(fā)就會(huì)不斷的報(bào)以下三個(gè)錯(cuò)誤:



2017/12/25 09:37:03 [error] 22582#0: *16081 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"

2017/12/25 09:37:03 [error] 22582#0: *16081 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"

2017/12/25 09:46:31 [error] 22581#0: *233603 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"



這個(gè)其實(shí)是考驗(yàn)一個(gè)框架的功力。我簡(jiǎn)單看了一下we7源碼,數(shù)據(jù)庫(kù)連接全是胡扯,就一個(gè)pdo對(duì)象做了單例(php的單例只能做到Java單例的20%)。完全沒有連接池的概念。再仔細(xì)看看ab的結(jié)果


這也就難怪請(qǐng)求越多死的越多了。更可怕的是一個(gè)錯(cuò)誤溢出消耗的cpu資源是正常的完整請(qǐng)求的三倍。

3.高級(jí)優(yōu)化思路

大致看了tp5的源碼,tp5是有數(shù)據(jù)庫(kù)連接池。但是對(duì)于沒有常住內(nèi)存進(jìn)程的php來(lái)說(shuō),然并卵啊。相比較而言Java就做的比較好,參考c3p0數(shù)據(jù)庫(kù)連接池原理。假使就想用php復(fù)用mysql連接池呢?可以使用swoole來(lái)實(shí)現(xiàn)。如果你僅僅做到了這一步,我覺得還不夠??梢詤⒖紃edis的pipeline設(shè)計(jì)一個(gè)緩沖池批量給mysql服務(wù)器同步數(shù)據(jù)。如果再配合上swoole的異步io就更好了。


fpm是使用進(jìn)程模型做計(jì)算密集處理的。以前在看python的協(xié)程、線程和進(jìn)程的時(shí)候有“io密集型用協(xié)程,計(jì)算密集型用進(jìn)程”的說(shuō)法。線程切換能占用近1/3的cpu確實(shí)很可怕。如果fpm能用協(xié)程模型實(shí)現(xiàn)著實(shí)能提高很高的效率。另外一條路子個(gè)人認(rèn)為也是php未來(lái)的一個(gè)趨勢(shì)——jit技術(shù)。難道只有我一個(gè)人覺得既然nginx 都已經(jīng)做了多worker、io復(fù)用、請(qǐng)求排隊(duì)這些操作了,fpm豈不是很多余嗎?未來(lái)一定會(huì)有人用php實(shí)現(xiàn)一個(gè)和OpenRest類似的東西。

在很大的請(qǐng)求量下,頻繁的寫入日志(nginx log)也是一個(gè)很頭疼的問題。同樣的nginx應(yīng)該提供一種批量寫入日志/延遲寫入日志的技術(shù)。這點(diǎn)我沒有驗(yàn)證,不知道nginx或者Tengine有沒有實(shí)現(xiàn)類似的功能。



?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒有聽過(guò)Nginx?那么一定聽過(guò)它的“同行”Apache吧!Ngi...
    JokerW閱讀 33,011評(píng)論 24 1,002
  • 一、MemCache簡(jiǎn)介 session MemCache是一個(gè)自由、源碼開放、高性能、分布式的分布式內(nèi)存對(duì)象緩存...
    李偉銘MIng閱讀 3,993評(píng)論 2 13
  • Nginx簡(jiǎn)介 解決基于進(jìn)程模型產(chǎn)生的C10K問題,請(qǐng)求時(shí)即使無(wú)狀態(tài)連接如web服務(wù)都無(wú)法達(dá)到并發(fā)響應(yīng)量級(jí)一萬(wàn)的現(xiàn)...
    魏鎮(zhèn)坪閱讀 2,205評(píng)論 0 9
  • ——11.30補(bǔ)充—— 分享一些個(gè)人簡(jiǎn)單的理解 “你,痛苦么?” 人的痛苦有兩種: 想要發(fā)生的事沒發(fā)生 不想發(fā)生的...
    捍道閱讀 883評(píng)論 0 3
  • 間:2012-04-23 今天天空有烏云,下著蒙蒙小雨。仍然擋不住我們夏令營(yíng)的小隊(duì)友的熱情。大家一路歡聲笑語(yǔ)坐著大...
    蘇睿昕閱讀 641評(píng)論 0 1

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