歡迎來到「我是真的狗雜談世界」,關(guān)注不迷路
背景
最近一個項(xiàng)目上線前QA對壓測結(jié)果不是很滿意(并且表示之前的項(xiàng)目壓測結(jié)果也都不理想),于是我在上線后(上線前是肯定來不及了)開始了一輪性能測試、排查和優(yōu)化,記錄一下整個過程。
思考過程
基礎(chǔ)信息
QA同學(xué)提供的壓測環(huán)境與結(jié)論:
- 施壓側(cè):
- 并發(fā)度100~300;
- 持續(xù)運(yùn)行120~300秒;
- 被壓側(cè):
- 單副本資源1C2G;
- 副本數(shù)1~4;
- 結(jié)果表現(xiàn):
- CPU:單副本100%(但有時出現(xiàn)某副本100%,其他副本60~80%左右);
- 內(nèi)存:單副本15~20%(但有時出現(xiàn)某副本高至50%)
- QPS:單副本100~120;
- 響應(yīng)耗時:Avg(487~596ms);50TH(19~27ms);90TH(1867~3099ms);95TH(2409~3902ms);99TH(4460~7002ms);MAX(8589~13298ms);
核心問題
關(guān)于性能、壓測等相關(guān)概念可參考「Foundation 11.性能是什么」
- QPS表現(xiàn)較低;
- CPU占用過高,很快被打滿;
- 響應(yīng)耗時存在少量(90TH以上)過高;
當(dāng)前這三者是有關(guān)聯(lián)的,當(dāng)前看來單個請求對于CPU資源需求較高,導(dǎo)致在小并發(fā)下CPU資源已占滿;
隨著并發(fā)度增高,系統(tǒng)通過頻繁調(diào)度來分配CPU資源,調(diào)度磨損增加(用于處理業(yè)務(wù)邏輯的比例降低);
因此CPU占用過高也會一定程度拖累響應(yīng)耗時、QPS表現(xiàn)。
懷疑方向
- 硬件性能:之前有發(fā)現(xiàn)壓測環(huán)境結(jié)果較比生產(chǎn)環(huán)境低,且兩側(cè)環(huán)境為獨(dú)立的集群,因此懷疑兩側(cè)集群節(jié)點(diǎn)本身硬件性能差異較大;
- 執(zhí)行過程:由于是PHP FPM模式下運(yùn)行的服務(wù),F(xiàn)astCGI處理過程、PHP代碼解釋執(zhí)行過程等都可能造成CPU資源的占用、耗時;
- IO阻塞度:業(yè)務(wù)邏輯中復(fù)雜(多次)同步阻塞請求(三方HTTP接口、MySQL、Redis)較比簡單(少次)會造成請求響應(yīng)需要時間變長,降低QPS;
- 短連資源:整個服務(wù)對三方HTTP接口、MySQL、Redis都采用的短連,連接僅在請求周期內(nèi)復(fù)用,請求結(jié)束后釋放,對于連接的頻繁創(chuàng)建銷毀也會占用CPU資源、耗時;
- 框架磨損:新版開發(fā)框架投入使用后沒有太關(guān)注性能磨損問題,理論上這塊一定會存在磨損,只是程度和關(guān)鍵磨損點(diǎn)問題。
排查方法
(盡量)控制其他變量保持相同的情況下,針對要排查的環(huán)節(jié)、對象進(jìn)行多組壓測對比,記錄并分析得出結(jié)論。
實(shí)踐與結(jié)論
定位基準(zhǔn)
由于QA提供的結(jié)論看起來存在很多不穩(wěn)定性,因此我決定在壓測環(huán)境上基于該項(xiàng)目先進(jìn)行一波測試,作為后續(xù)對比、分析、研究等排查工作的基準(zhǔn)。
第一波測試
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2C2G | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 2 | 980 | - | - | - | - | - | - | 80 |
| 2C2G | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 2 | 490 | - | - | - | - | - | - | 90 |
從第一波測試記錄數(shù)據(jù)(因?yàn)镼PS表現(xiàn)已發(fā)生過于不穩(wěn)定現(xiàn)象了,其他數(shù)據(jù)就暫時沒有關(guān)注和記錄)很容易發(fā)現(xiàn),除了我控制住的變量外,一定還存在一個我沒發(fā)現(xiàn)的變量影響了壓測表現(xiàn);
而這兩次測試存在的變量只有兩個:
- 測試時間:由于壓測服務(wù)做了串行控制(同一個時間點(diǎn)只能最多一個壓測任務(wù)執(zhí)行),上述兩波測試是在不同的時間點(diǎn)進(jìn)行的。
- 被測副本:由于壓測環(huán)境需要很多配置成本,沒有分別配置兩套壓測環(huán)境,上述兩波測試之間進(jìn)行了應(yīng)用副本重建(重新構(gòu)建了服務(wù))。
為了進(jìn)一步排查上述兩個變量,我每次多次重建副本,每次重建副本后進(jìn)行相隔一段時間的多組壓測,現(xiàn)象如下:
- 相同副本(不重建副本)中的表現(xiàn)是穩(wěn)定的(如果是500上下則一直是500上下,如果是1000上下則一直是1000上下),甚至到第二天仍舊是穩(wěn)定的;
- 不同副本(重建副本)時的表現(xiàn)會發(fā)生波動(比如500變成1000,1000變500),但也不是每次重建都必然發(fā)生波動切換。
基于上述現(xiàn)象,基本可以排除時間差異,而懷疑副本調(diào)度到的節(jié)點(diǎn)的硬件或其他基礎(chǔ)設(shè)施的差異導(dǎo)致;
我將此問題報告給服務(wù)器基礎(chǔ)設(shè)施團(tuán)隊后協(xié)助排查定位,最終發(fā)現(xiàn)壓測環(huán)境4個節(jié)點(diǎn)其中1個節(jié)點(diǎn)的CPU基頻在1.5~3.5GHz之間動態(tài)波動(正常4個節(jié)點(diǎn)都應(yīng)該是3.5GHz);
在他們解決問題的同時,我管他們要了一個獨(dú)立節(jié)點(diǎn)來繼續(xù)我的測試,后面所有資源將按照下述描述:
- 新節(jié)點(diǎn):代表管他們要來的獨(dú)立節(jié)點(diǎn),性能本身很差,2C表現(xiàn)還不如原節(jié)點(diǎn)1C好;
- 原節(jié)點(diǎn):代表除CPU異常節(jié)點(diǎn)之外的壓測環(huán)境節(jié)點(diǎn)(理論上與生產(chǎn)環(huán)境節(jié)點(diǎn)性能仍有差距);
- X號副本:代表副本重建,相同的X代表副本未經(jīng)過重建;原節(jié)點(diǎn)有意義(由于壓測環(huán)境節(jié)點(diǎn)仍舊會有一些細(xì)微差異),新節(jié)點(diǎn)無意義(就只有一個節(jié)點(diǎn));
- 健康檢查:代表業(yè)務(wù)上一個接口直接返回,沒有業(yè)務(wù)邏輯和三方請求;
- 簡單邏輯:代表業(yè)務(wù)上一個接口包含一個MySQL查詢;
- 簡單邏輯*x:代表業(yè)務(wù)上一個接口包含x個相同的MySQL查詢;
- 復(fù)雜邏輯:代表該項(xiàng)目業(yè)務(wù)真實(shí)邏輯(一個接口包含2~8次MySQL、Redis、HTTP接口請求等);
繼續(xù)測試
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 1 | 162 | 5.63 | 6 | 6 | 6 | 8 | 20 | 31 |
| 1C2G;原節(jié)點(diǎn);1號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 1 | 496 | 1.63 | 2 | 2 | 2 | 2 | 217 | 80 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 1 | 484 | 1.67 | 2 | 2 | 2 | 3 | 138 | 73 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 5 | 526 | 8.66 | 6 | 7 | 40 | 47 | 1686 | 100 |
| 1C2G;原節(jié)點(diǎn);1號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 5 | 660 | 6.43 | 2 | 2 | 72 | 77 | 2300 | 100 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 5 | 624 | 6.9 | 2 | 3 | 73 | 78 | 900 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 20 | 462 | 41.74 | 7 | 93 | 93 | 95 | 1858 | 100 |
| 1C2G;原節(jié)點(diǎn);1號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 20 | 530 | 36.32 | 3 | 96 | 96 | 97 | 2402 | 100 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 20 | 509 | 38.11 | 3 | 96 | 97 | 98 | 1715 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 50 | 371 | 129.5 | 102 | 200 | 203 | 298 | 2023 | 100 |
| 1C2G;原節(jié)點(diǎn);1號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 50 | 472 | 104.12 | 100 | 195 | 197 | 202 | 3056 | 100 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 50 | 446 | 110.3 | 100 | 197 | 199 | 297 | 1827 | 94 |
- 新節(jié)點(diǎn)在并發(fā)1~5之間達(dá)到CPU100%,QPS最高表現(xiàn)也在這之間達(dá)到(理論上會略高于526),表現(xiàn)確實(shí)很拉垮。。。
- 原節(jié)點(diǎn)在并發(fā)1~5之間達(dá)到CPU100%,QPS最高表現(xiàn)也在這之間達(dá)到(理論上會略高于660/624)。
- CPU未打滿時,隨著并發(fā)度提高,QPS、CPU占用率也隨之增長,響應(yīng)耗時保持穩(wěn)定;
- CPU打滿后,隨著并發(fā)度提高,QPS先穩(wěn)定后逐步降低,響應(yīng)耗時逐步增大。
PHP8&Jit
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 1 | 83 | 11.13 | 11 | 17 | 18 | 19 | 158 | 30 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache | 新框架+健康檢查 | 1 | 84 | 11.04 | 11 | 17 | 18 | 19 | 88 | 30 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 1 | 82 | 11.2 | 11 | 17 | 18 | 19 | 1674 | 38 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 5 | 287 | 15.67 | 13 | 42 | 48 | 57 | 1682 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache | 新框架+健康檢查 | 5 | 290 | 15.66 | 12 | 42 | 48 | 58 | 171 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 5 | 288 | 15.87 | 12 | 42 | 48 | 59 | 1730 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 20 | 272 | 70.67 | 94 | 103 | 107 | 192 | 1740 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache | 新框架+健康檢查 | 20 | 273 | 70.5 | 94 | 103 | 107 | 193 | 2081 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 20 | 272 | 71.34 | 94 | 103 | 107 | 192 | 1807 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 50 | 239 | 200.04 | 200 | 302 | 398 | 497 | 1998 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache | 新框架+健康檢查 | 50 | 251 | 195.91 | 199 | 302 | 395 | 489 | 2105 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 50 | 249 | 197.18 | 200 | 302 | 396 | 492 | 2183 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查 | 100 | 216 | 454.79 | 403 | 797 | 901 | 1200 | 2664 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache | 新框架+健康檢查 | 100 | 225 | 438.31 | 404 | 746 | 896 | 1193 | 2542 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 100 | 222 | 444.76 | 407 | 744.9 | 892 | 1099 | 2443 | 100 |
- PHP8.0較比7.4在業(yè)務(wù)代碼不動的情況下(基于7.4及之前語法)沒有直接的性能提升;
- CPU消耗大頭不在opcache轉(zhuǎn)machine code環(huán)節(jié)(想想也是);
- PHP8.0+Jit目前無法帶來并發(fā)和性能表現(xiàn)的提升。
IO堵塞次數(shù)
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 1 | 156 | 2.71 | 6 | 6 | 6 | 8 | 198 | 30 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯 | 1 | 97 | 9.72 | 10 | 10 | 11 | 13 | 27 | 35 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯*5 | 1 | 75 | 12.58 | 12 | 13 | 14 | 16 | 1607 | 27 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+復(fù)雜邏輯 | 1 | 82 | 11.2 | 11 | 17 | 18 | 19 | 1674 | 38 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 5 | 508 | 9.09 | 6 | 8 | 41 | 48 | 1653 | 99 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯 | 5 | 297 | 15.68 | 10 | 44 | 51 | 60 | 2046 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯*5 | 5 | 282 | 16.51 | 13 | 34 | 43 | 53 | 1809 | 98 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+復(fù)雜邏輯 | 5 | 288 | 15.87 | 12 | 42 | 48 | 59 | 1730 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 20 | 451 | 42.92 | 8 | 93 | 94 | 96 | 1843 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯 | 20 | 275 | 70.91 | 94 | 101 | 104 | 191 | 1740 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯*5 | 20 | 269 | 72.79 | 92 | 101 | 105 | 188 | 1809 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+復(fù)雜邏輯 | 20 | 272 | 71.34 | 94 | 103 | 107 | 192 | 1807 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 50 | 386 | 126.52 | 103 | 199 | 202 | 296 | 1989 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯 | 50 | 247 | 197.5 | 199 | 299 | 303 | 404 | 2079 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯*5 | 50 | 246 | 200.26 | 199 | 298 | 301 | 400 | 2067 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+復(fù)雜邏輯 | 50 | 249 | 197.18 | 200 | 302 | 396 | 492 | 2183 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+健康檢查 | 100 | 357 | 273.75 | 292 | 399 | 473.65 | 510 | 2089 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯 | 100 | 233 | 424.72 | 402 | 602 | 697 | 897 | 2389 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+簡單邏輯*5 | 100 | 226 | 438.53 | 403 | 604 | 699 | 852.98 | 2417 | 100 |
| 2C2G;新節(jié)點(diǎn);0號副本 | PHP-FPM8.0+OPcache+JIt | 新框架+復(fù)雜邏輯 | 100 | 222 | 444.76 | 407 | 744.9 | 892 | 1099 | 2443 | 100 |
- 邏輯中不同程度的IO會導(dǎo)致單次請求的響應(yīng)耗時增加,但對CPU的占用率影響較?。?/li>
- 請求響應(yīng)耗時高阻塞IO較比低阻塞IO普遍增加;
- 并發(fā)度未將CPU打滿時,高阻塞IO較比低阻塞IO的QPS表現(xiàn)要低;
- 當(dāng)并發(fā)度提升將CPU打滿后,高阻塞IO較比低阻塞IO的QPS表現(xiàn)幾乎一致
PDO長連接
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 1 | 139 | 6.56 | 5 | 6 | 6 | 15 | 2112 | 40 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 1 | 207 | 4.23 | 3 | 4 | 4 | 9 | 1337 | 45 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 2 | 241 | 7.33 | 5 | 6 | 12 | 33 | 1077 | 83 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 2 | 356 | 4.62 | 3 | 4 | 6 | 22 | 1060 | 91 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 5 | 274 | 16.37 | 5 | 66 | 74 | 86 | 1722 | 100 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 5 | 427 | 10.33 | 3 | 9 | 67 | 73 | 1293 | 100 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 20 | 265 | 73.19 | 93 | 103 | 196 | 302 | 1778 | 88 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 20 | 393 | 49.31 | 12 | 97 | 100 | 103 | 1742 | 95 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 50 | 253 | 195.05 | 198 | 300 | 398 | 599.79 | 1914 | 88 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 50 | 345 | 142.96 | 102 | 200 | 202 | 300 | 2136 | 92 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+短連 | 100 | 241 | 401.15 | 397 | 601 | 705 | 1203.1 | 2644 | 99 |
| 1C2G;原節(jié)點(diǎn);2號副本 | PHP-FPM7.4+OPcache | 新框架+簡單邏輯+長連 | 100 | 325 | 303.06 | 299 | 496 | 501 | 701 | 2205 | 100 |
網(wǎng)絡(luò)連接資源復(fù)用較比不復(fù)用在當(dāng)前業(yè)務(wù)特點(diǎn)下能帶來:
- 提升35~55%QPS;
- 降低25~37%響應(yīng)耗時。
框架截斷
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 入口文件直接返回 | 20 | 6505 | 2.72 | 1 | 1 | 2 | 68 | 1774 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 入口文件解析完請求 | 20 | 5956 | 2.72 | 1 | 1 | 1 | 69 | 1832 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 引入自動加載之后 | 20 | 4341 | 3.61 | 1 | 1 | 2 | 77 | 2108 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 加載項(xiàng)目配置之后 | 20 | 2278 | 8.16 | 1 | 2 | 86 | 89 | 1101 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 加載底層配置之后 | 20 | 849 | 23.04 | 2 | 94 | 94 | 95 | 1867 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 注冊全部請求接口之后 | 20 | 630 | 30.97 | 2 | 95 | 96 | 97 | 1899 | 100 |
| 1C2G;原節(jié)點(diǎn);3號副本 | PHP-FPM7.4+OPcache | 健康檢查完整處理 | 20 | 516 | 37.62 | 3 | 96 | 97 | 98 | 1878 | 77 |
磨損主要發(fā)生環(huán)節(jié):
- 引入自動加載(composer autoload);
- 加載項(xiàng)目配置;
- 加載底層配置。
優(yōu)化方向
短連改長連
將請求MySQL、Redis的連接模式改成長連接,將連接周期由請求級別延伸至FPM進(jìn)程級別,以此減少連接創(chuàng)建銷毀操作降低CPU占用、減少響應(yīng)耗時提升性能整體表現(xiàn)。
但考慮到:
- MySQL、Redis連接數(shù)將幾乎與FPM開啟的Work進(jìn)程數(shù)量一致;
- 多項(xiàng)目、多組共用MySQL、Redis;
- 短連模式下,QPS過高反而會帶來本地端口用盡的問題(具體見本文最后)。
決定暫時不采用此方案。
緩存項(xiàng)目與底層配置
將原先每次請求都讀取多個ini配置文件并解析結(jié)構(gòu)改造成初始化時讀取并解析然后回寫為php數(shù)組文件:
- 避免config map的性能影響(原先這些ini配置都是通過config map掛載進(jìn)項(xiàng)目);
- 節(jié)省ini配置解析成本(php文件直接借用php本身opcache、jit優(yōu)化就足夠)。
我將這個優(yōu)化做到了新框架的后續(xù)版本中,并且壓測驗(yàn)證:
| 資源情況 | 程序情況 | 接口復(fù)雜度 | 并發(fā)度 | QPS | AVG | 50TH | 90TH | 95TH | 99TH | MAX | CPU(峰值) |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 1 | 480 | 1.6 | 2 | 2 | 2 | 2 | 220 | 77 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 1 | 705 | 1.05 | 1 | 1 | 2 | 2 | 1775 | 79 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 2 | 619 | 2.55 | 2 | 2 | 2 | 35 | 2526 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 2 | 1083 | 1.54 | 1 | 1 | 2 | 26 | 2275 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 5 | 659 | 6.8 | 2 | 2 | 72 | 77 | 2409 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 5 | 1060 | 4.36 | 1 | 2 | 2 | 72 | 2335 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 20 | 530 | 37.09 | 3 | 96 | 97 | 98 | 2398 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 20 | 970 | 20.18 | 2 | 93 | 94 | 95 | 2601 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 50 | 469 | 105.58 | 100 | 196 | 198 | 231.99 | 2799 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 50 | 946 | 52.22 | 90 | 98 | 99 | 103 | 2901 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+不緩存配置 | 100 | 415 | 239.43 | 202 | 394 | 400 | 598 | 3000 | 100 |
| 1C2G;原節(jié)點(diǎn);4號副本 | PHP-FPM7.4+OPcache | 新框架+健康檢查+緩存配置 | 100 | 920 | 107.89 | 100 | 195 | 199 | 289 | 2609 | 100 |
緩存配置較比不緩存對沒有連接和阻塞IO的邏輯能帶來:
- 提升46~121%QPS;
- 降低34~54%響應(yīng)耗時;
- 并發(fā)度越高,效果越明顯(在可承受的并發(fā)度范圍內(nèi))。
我也對帶上不同程度業(yè)務(wù)邏輯的場景進(jìn)行了測試;
簡單邏輯下緩存配置較比不緩存能帶來:
- 提升9~14%QPS;
- 降低9~12%響應(yīng)耗時;
復(fù)雜邏輯下緩存配置較比不緩存能帶來:
- 提升4~17%QPS;
- 降低5~14%響應(yīng)耗時;
換運(yùn)行模式
如果前面兩者都不可用或者不能滿足需要的時候,可以考慮更換當(dāng)前這種FPM的運(yùn)行模式,改用Cli+異步模型:
- 天生可以使用MySQL、Redis、HTTP等連接池技術(shù),又不需要當(dāng)心連接數(shù)過多的問題;
- 進(jìn)一步減少代碼解釋執(zhí)行過程的消耗,Opcache和Jit技術(shù)可以進(jìn)一步發(fā)揮作用;
- 異步搭配yield/Fiber,或是swoole封裝的異步庫充分利用CPU,提升單接口響應(yīng)效率。
但這樣無疑是存在較高的成本和風(fēng)險的:
- 現(xiàn)有的框架、庫包都是基于同步阻塞封裝的,異步可能帶來并發(fā)爭競隱患;
- FPM同步阻塞模型犧牲一定性能帶來的是開發(fā)效率和門檻的優(yōu)勢,如果換成異步模型,對開發(fā)人員和業(yè)務(wù)無疑會帶來更高的門檻和風(fēng)險;
- 類似swoole+異步協(xié)程其實(shí)幾乎都相當(dāng)于換了大半個語言了。
整體結(jié)論
- 目前1C2G在壓測環(huán)境一般的邏輯都可以達(dá)到250甚至更高了,暫時滿足我們的業(yè)務(wù)需求(更高的性能表現(xiàn)可以通過擴(kuò)展副本來實(shí)現(xiàn));
- 還有很多的優(yōu)化方案和空間,但考慮到團(tuán)隊目前的情況和方案的成本與風(fēng)險,暫時不開展這類方案。
短連單副本QPS過高的問題
當(dāng)前的系統(tǒng)設(shè)置為:
- 本地可用客戶端端口范圍:32768~60999
- time wait狀態(tài)快速回收和重用:沒有權(quán)限,但根據(jù)現(xiàn)象觀察應(yīng)該是60s
當(dāng)我調(diào)大CPU資源為2C壓測一個簡單邏輯(每個請求會創(chuàng)建一個MySQL連接,請求結(jié)束就主動close連接)時,QPS達(dá)到500上下,但最后幾秒會出現(xiàn)本地端口用盡的問題。