在線和并發(fā)請求)
容量測試到底測什么一次對話理清同時(shí)在線和并發(fā)請求和同事討論容量測試發(fā)現(xiàn)很多人把同時(shí)在線和并發(fā)請求攪在一起。這篇把這段對話記錄下來幫你看清容量的本質(zhì)。文章目錄容量測試到底測什么一次對話理清同時(shí)在線和并發(fā)請求一、起點(diǎn)一個(gè)常見的判斷1.1 同事的初始判斷1.2 先搞清兩個(gè)概念二、如果只看同時(shí)在線容量確實(shí)可以非常大2.1 無狀態(tài)架構(gòu)在線用戶幾乎不花錢2.2 那有session的系統(tǒng)呢三、但是在線人數(shù)越高并發(fā)請求越高3.1 統(tǒng)計(jì)關(guān)系3.2 容量和并發(fā)是一個(gè)連續(xù)光譜3.3 一個(gè)實(shí)際例子四、并發(fā)請求的真正瓶頸在哪4.1 一個(gè)請求進(jìn)來的真實(shí)開銷4.2 瓶頸清單4.3 一個(gè)并發(fā)請求的開銷五、容量測試到底測什么5.1 測的是第一個(gè)被打破的瓶頸5.2 各層監(jiān)控指標(biāo)5.3 常見場景六、總結(jié)6.1 三個(gè)結(jié)論6.2 一句話一、起點(diǎn)一個(gè)常見的判斷1.1 同事的初始判斷同事做政務(wù)系統(tǒng)要搞容量測試。他的判斷是容量測試應(yīng)該只和服務(wù)端內(nèi)存有關(guān)系吧session或者jwt也占用不了多少內(nèi)存容量應(yīng)該可以非常大。乍一看沒毛病——一個(gè)JWT字符串幾百字節(jié)一個(gè)session對象也就存點(diǎn)用戶信息內(nèi)存開銷確實(shí)不大。那同時(shí)在線幾萬人內(nèi)存也吃不了多少。容量瓶頸不該是內(nèi)存吧但這個(gè)判斷有一個(gè)隱藏的概念混淆。1.2 先搞清兩個(gè)概念同時(shí)在線容量并發(fā)請求含義多少用戶登錄著、在用系統(tǒng)服務(wù)器同一時(shí)刻在處理多少請求對服務(wù)器的直接壓力JWT幾乎為零session很小每個(gè)請求吃線程連接CPU瓶頸在哪幾乎沒有線程池/連接池/CPU/數(shù)據(jù)庫這是兩個(gè)完全不同的東西。很多開發(fā)者嘴上說著系統(tǒng)容量要支撐一萬用戶實(shí)際上擔(dān)心的是一萬用戶同時(shí)點(diǎn)按鈕服務(wù)器扛不扛得住——前者是容量問題后者是并發(fā)問題。二、如果只看同時(shí)在線容量確實(shí)可以非常大2.1 無狀態(tài)架構(gòu)在線用戶幾乎不花錢現(xiàn)在的系統(tǒng)基本都用JWT。用戶登錄后拿到一個(gè)tokentoken存在客戶端瀏覽器localStorage或Cookie。服務(wù)器不存任何東西。用戶登錄 → 服務(wù)器簽發(fā)JWT → 返回給客戶端 ↓ 用戶后續(xù)請求 → 帶上JWT → 服務(wù)器驗(yàn)簽 → 處理請求 ↓ 請求結(jié)束 → 服務(wù)器什么都不留用戶拿不到token時(shí)在瀏覽頁面、填表單、看數(shù)據(jù)——這段時(shí)間對服務(wù)器來說這個(gè)用戶不存在。服務(wù)器不給他分配線程、不分配連接、不分配內(nèi)存。所以同時(shí)在線10萬人和100人對服務(wù)器來說沒區(qū)別——因?yàn)榇蟛糠衷诰€用戶此刻沒有在發(fā)請求。2.2 那有session的系統(tǒng)呢有同事會(huì)說我們的系統(tǒng)用Tomcat的HttpSession每個(gè)用戶在服務(wù)端存一份session這不就占內(nèi)存了嗎算一筆賬。一個(gè)session里實(shí)際存什么數(shù)據(jù)大小估算用戶信息id、姓名、賬號~200字節(jié)機(jī)構(gòu)信息id、名稱~100字節(jié)角色列表幾個(gè)角色I(xiàn)D~50字節(jié)權(quán)限標(biāo)識如果是角色I(xiàn)D而非逐個(gè)權(quán)限~100字節(jié)合計(jì)不到1KB1000人在線session內(nèi)存不到1MB。10000人在線也就幾MB。跟服務(wù)器動(dòng)輒幾個(gè)G的內(nèi)存比完全可以忽略。所以無論session還是JWT在線人數(shù)本身都不是瓶頸。同事最初的判斷方向是對的——容量確實(shí)可以非常大。三、但是在線人數(shù)越高并發(fā)請求越高3.1 統(tǒng)計(jì)關(guān)系到這里同事說那容量不是問題啊隨便扛。但這里有個(gè)統(tǒng)計(jì)關(guān)系一個(gè)系統(tǒng)在相關(guān)條件不變化同時(shí)在線用戶數(shù)量越多并發(fā)會(huì)越高。100個(gè)人在線同一時(shí)刻可能有5個(gè)人在點(diǎn)按鈕。10000個(gè)人在線同一時(shí)刻可能有500個(gè)人在點(diǎn)。在線人數(shù)上去了并發(fā)請求自然跟著上去。并發(fā)請求數(shù) ≈ 同時(shí)在線人數(shù) × 用戶活躍率 用戶活躍率 用戶在單位時(shí)間內(nèi)發(fā)起請求的概率不同系統(tǒng)的用戶活躍率差異極大系統(tǒng)類型用戶活躍率說明政務(wù)OA低大部分時(shí)間在看頁面、填表幾秒點(diǎn)一次電商日常中瀏覽、加購物車、搜索電商秒殺極高所有人同時(shí)點(diǎn)搶購按鈕即時(shí)通訊高收發(fā)消息、狀態(tài)同步幾乎一直在請求所以不能脫離用戶行為談容量。容量不是孤立的能掛多少在線用戶而是這些在線用戶產(chǎn)生的高并發(fā)服務(wù)器扛不扛得住。3.2 容量和并發(fā)是一個(gè)連續(xù)光譜容量測試 并發(fā)測試 能掛多少在線用戶 在線用戶產(chǎn)生的高并發(fā)扛不扛得住 ←————————————————————————————→ 統(tǒng)計(jì)橋梁用戶活躍率兩者不是對立的是同一條鏈路上的兩端。容量測試關(guān)注左端——系統(tǒng)能容納多少在線用戶。并發(fā)測試關(guān)注右端——這些用戶產(chǎn)生的請求高峰能不能扛。中間的橋梁就是用戶行為模式。3.3 一個(gè)實(shí)際例子某政務(wù)系統(tǒng)預(yù)期5000人同時(shí)在線。做容量測試時(shí)要算的不是5000個(gè)session占多少內(nèi)存而是5000人在線 × 用戶活躍率假設(shè)10%在同時(shí)操作 500個(gè)并發(fā)請求 ↓ Tomcat默認(rèn)maxThreads200 → 不夠要調(diào)大 數(shù)據(jù)庫連接池默認(rèn)20 → 遠(yuǎn)遠(yuǎn)不夠要調(diào)大 ↓ 這才是容量測試要回答的問題瓶頸不在5000人在線瓶頸在5000人產(chǎn)生的500個(gè)并發(fā)請求。四、并發(fā)請求的真正瓶頸在哪4.1 一個(gè)請求進(jìn)來的真實(shí)開銷既然瓶頸在并發(fā)請求那一個(gè)請求到底吃服務(wù)器什么資源HTTP請求到達(dá) ↓ Tomcat線程池分配線程maxThreads默認(rèn)200 ↓ 從連接池拿數(shù)據(jù)庫連接默認(rèn)8~20個(gè) ↓ 執(zhí)行業(yè)務(wù)邏輯CPU計(jì)算、JWT驗(yàn)簽、序列化 ↓ 查數(shù)據(jù)庫可能等待鎖、等待IO ↓ 返回響應(yīng) ↓ 釋放線程和連接每一環(huán)都可能先于內(nèi)存成為瓶頸。4.2 瓶頸清單瓶頸默認(rèn)上限說明線程池Tomcat默認(rèn)200200個(gè)并發(fā)請求就開始排隊(duì)跟內(nèi)存無關(guān)數(shù)據(jù)庫連接池Druid/HikariCP默認(rèn)8~20拿不到連接的請求要么等要么超時(shí)CPU看核數(shù)JWT驗(yàn)簽、序列化、加解密、業(yè)務(wù)計(jì)算數(shù)據(jù)庫本身幾百~上千并發(fā)鎖競爭、慢查詢數(shù)據(jù)庫比應(yīng)用服務(wù)器先扛不住內(nèi)存看配置session/JWT確實(shí)占不了多少4.3 一個(gè)并發(fā)請求的開銷不要把一個(gè)用戶在線和一個(gè)請求處理搞混資源一個(gè)在線用戶空閑一個(gè)正在處理的請求線程無一個(gè)線程棧空間512KB~1MB數(shù)據(jù)庫連接無一個(gè)連接連接對象會(huì)話狀態(tài)內(nèi)存session/JWT ~1KB結(jié)果集、序列化緩沖、臨時(shí)對象CPU無JWT驗(yàn)簽、業(yè)務(wù)計(jì)算、序列化1000個(gè)并發(fā)請求光線程棧就吃掉1GB內(nèi)存。而且線程切換的CPU開銷比內(nèi)存更致命。所以容量可以非常大這句話對了一半——在線用戶的容量確實(shí)很大但他們產(chǎn)生的并發(fā)請求打到的瓶頸不在內(nèi)存在別的地方。五、容量測試到底測什么5.1 測的是第一個(gè)被打破的瓶頸容量測試不是應(yīng)用服務(wù)器內(nèi)存能掛多少session而是從用戶請求到數(shù)據(jù)庫返回這條鏈路上哪個(gè)環(huán)節(jié)最先斷。不斷加壓觀察哪個(gè)指標(biāo)先異常逐漸增加在線用戶數(shù)或直接加并發(fā)請求 ↓ 監(jiān)控每一層的指標(biāo) ↓ 第一個(gè)先撐不住的環(huán)節(jié) 系統(tǒng)的真實(shí)容量上限5.2 各層監(jiān)控指標(biāo)層次監(jiān)控什么異常表現(xiàn)應(yīng)用服務(wù)器CPU、內(nèi)存、線程數(shù)、GCCPU持續(xù)80%、頻繁Full GCWeb容器活躍線程數(shù)、請求隊(duì)列長度線程滿、請求排隊(duì)超時(shí)連接池活躍連接數(shù)、等待連接數(shù)連接耗盡、請求等待數(shù)據(jù)庫活躍會(huì)話數(shù)、鎖等待、慢SQL鎖沖突、SQL變慢網(wǎng)絡(luò)帶寬、連接數(shù)、丟包響應(yīng)時(shí)間飆升5.3 常見場景場景最先斷的環(huán)節(jié)解法方向政務(wù)OA數(shù)據(jù)庫連接池默認(rèn)太小調(diào)大連接池上限查詢密集型數(shù)據(jù)庫慢SQL加索引、優(yōu)化SQL、讀寫分離計(jì)算密集型應(yīng)用服務(wù)器CPU加機(jī)器、異步化秒殺類數(shù)據(jù)庫行鎖隊(duì)列削峰、緩存六、總結(jié)6.1 三個(gè)結(jié)論同時(shí)在線和并發(fā)請求是兩個(gè)概念——在線用戶的內(nèi)存開銷確實(shí)很小session或JWT都不到1KB可以忽略但在線人數(shù)越高并發(fā)越高——兩者通過用戶活躍率關(guān)聯(lián)不能脫離用戶行為談容量瓶頸永遠(yuǎn)在并發(fā)請求層——線程池、連接池、CPU、數(shù)據(jù)庫這些才是容量上限的真正決定因素6.2 一句話容量測試不是測能掛多少用戶是測這些用戶一起點(diǎn)的時(shí)候哪個(gè)環(huán)節(jié)先斷。