你以為水平擴(kuò)展就是加機(jī)器?以為長(zhǎng)輪詢比短輪詢更省資源?這些"常識(shí)"可能正在拖垮你的系統(tǒng)。
這篇筆記來自一位工程師的真實(shí)學(xué)習(xí)整理,沒有理論堆砌,全是面試和實(shí)戰(zhàn)中踩過的坑。看完你會(huì)發(fā)現(xiàn):很多性能問題的根源,不是代碼寫得爛,是架構(gòu)選型時(shí)就選錯(cuò)了方向。
![]()
輪詢策略:短輪詢是性能殺手,但長(zhǎng)輪詢也不是萬能解
客戶端要實(shí)時(shí)拿到服務(wù)器更新,最土的辦法是短輪詢:每隔幾秒發(fā)一次請(qǐng)求問"有新消息嗎"。實(shí)現(xiàn)簡(jiǎn)單,問題在于空轉(zhuǎn)——90%的請(qǐng)求換來的都是"沒有更新",帶寬和CPU全浪費(fèi)在無效往返上。
長(zhǎng)輪詢看起來聰明:客戶端發(fā)請(qǐng)求后,服務(wù)器掛著不立刻響應(yīng),等有數(shù)據(jù)了再返回。省了點(diǎn)無效請(qǐng)求,但代價(jià)是服務(wù)器要維持大量掛起的連接。一個(gè)線程掛一個(gè)請(qǐng)求,幾千并發(fā)就能吃光線程池。
真正低延遲的場(chǎng)景,SSE(服務(wù)器推送事件)和WebSocket才是正解。SSE單向推送適合股票行情、新聞feed;WebSocket雙向通道適合聊天、協(xié)作編輯。但別急著上WebSocket——它維護(hù)長(zhǎng)連接的成本,在弱網(wǎng)環(huán)境下可能比輪詢更崩。
擴(kuò)展方向:垂直擴(kuò)展被嫌棄,但水平擴(kuò)展有隱形成本
加CPU加內(nèi)存叫垂直擴(kuò)展,加機(jī)器叫水平擴(kuò)展。業(yè)內(nèi)默認(rèn)水平擴(kuò)展更"優(yōu)雅",因?yàn)閱螜C(jī)總有天花板。但很多人忽略了:水平擴(kuò)展引入的復(fù)雜度,可能吃掉你省下的硬件錢。
分布式意味著數(shù)據(jù)一致性要重新設(shè)計(jì)。用戶A的請(qǐng)求打到機(jī)器1,用戶B的請(qǐng)求打到機(jī)器2,會(huì)話狀態(tài)怎么同步?數(shù)據(jù)庫分片后,一個(gè)查詢要跨多個(gè)節(jié)點(diǎn)聚合,延遲可能反而上升。Netflix能玩水平擴(kuò)展,是因?yàn)橛袑iT的團(tuán)隊(duì)做分布式調(diào)度——小團(tuán)隊(duì)硬上,等于給自己挖坑。
垂直擴(kuò)展在特定場(chǎng)景反而更香。內(nèi)部工具、低頻后臺(tái)任務(wù)、強(qiáng)一致性要求的財(cái)務(wù)系統(tǒng),單機(jī)MySQL配個(gè)好SSD,可能比分布式數(shù)據(jù)庫少睡很多覺。
負(fù)載均衡:不只是"把流量分到多臺(tái)機(jī)器"
很多人理解負(fù)載均衡就是輪詢:請(qǐng)求1給A,請(qǐng)求2給B,雨露均沾。但輪詢對(duì)計(jì)算密集型任務(wù)很蠢——A機(jī)器正在跑重任務(wù),新請(qǐng)求過來照樣塞給它。
最少連接數(shù)策略更聰明:看誰當(dāng)前處理的請(qǐng)求少,新請(qǐng)求給誰。加權(quán)策略適合異構(gòu)集群:新機(jī)器配置高,權(quán)重設(shè)大點(diǎn),老機(jī)器慢慢退居二線。會(huì)話保持(Sticky Session)解決狀態(tài)問題:同一個(gè)用戶的請(qǐng)求固定打到同一臺(tái)機(jī)器,但代價(jià)是某臺(tái)機(jī)器掛了,它的用戶全丟會(huì)話。
健康檢查是隱形剛需。負(fù)載均衡器得持續(xù)探測(cè)后端,發(fā)現(xiàn)某臺(tái)機(jī)器響應(yīng)慢了、報(bào)錯(cuò)多了,自動(dòng)踢出集群。沒有健康檢查的負(fù)載均衡,等于把雞蛋放在多個(gè)籃子里,但籃子之間用繩子綁著——一塌全塌。
緩存淘汰:LRU不是唯一答案,業(yè)務(wù)特征決定策略
緩存滿了刪誰?LRU(最近最少使用)是默認(rèn)答案,但假設(shè)你的緩存是熱點(diǎn)新聞,最新發(fā)布的文章反而應(yīng)該優(yōu)先保留,不管它現(xiàn)在被讀了多少次。這時(shí)候LFU(最不經(jīng)常使用)或者簡(jiǎn)單的時(shí)間過期(TTL)更合適。
更隱蔽的問題是緩存穿透:查詢一個(gè)不存在的數(shù)據(jù),緩存miss,打到數(shù)據(jù)庫,數(shù)據(jù)庫也查不到。攻擊者用隨機(jī)ID狂刷,數(shù)據(jù)庫直接崩。布隆過濾器或者緩存空值,是解決這類問題的標(biāo)準(zhǔn)套路。
緩存雪崩是另一個(gè)噩夢(mèng):大量key同時(shí)過期,請(qǐng)求雪崩式打到數(shù)據(jù)庫。給過期時(shí)間加隨機(jī)偏移,或者熱點(diǎn)數(shù)據(jù)永不過期+后臺(tái)異步刷新,才能避免整點(diǎn)事故。
代理與反向代理:方向搞反,安全模型全錯(cuò)
正向代理站在客戶端前面,幫用戶訪問外部資源——翻墻工具、公司內(nèi)網(wǎng)代理都是這類。反向代理站在服務(wù)器前面,用戶以為自己連的是目標(biāo)網(wǎng)站,實(shí)際連的是代理,再由代理決定哪臺(tái)后端服務(wù)器處理。
這個(gè)"反向"不是白叫的。它隱藏了后端拓?fù)洌粽呙磺迥阌卸嗌倥_(tái)服務(wù)器、什么IP。SSL終結(jié)也在這一層做:用戶到反向代理走HTTPS,代理到后端走HTTP,減少后端加解密開銷。但這也意味著反向代理成了單點(diǎn),它掛了全站癱瘓,高可用方案必須跟上。
API網(wǎng)關(guān)是反向代理的進(jìn)化版。不只是路由,還管認(rèn)證、限流、協(xié)議轉(zhuǎn)換。微服務(wù)架構(gòu)下,100個(gè)服務(wù)不可能各自做鑒權(quán),統(tǒng)一收口在網(wǎng)關(guān),后端只專注業(yè)務(wù)邏輯。但網(wǎng)關(guān)本身別寫復(fù)雜邏輯,否則它又成了新瓶頸。
WebSocket:雙向通信的代價(jià),很多人沒算清
HTTP是請(qǐng)求-響應(yīng)模式,問一句答一句,答完關(guān)門。WebSocket一次握手后連接保持,雙方隨時(shí)推送。聊天室、在線游戲、協(xié)同文檔,這些場(chǎng)景沒有WebSocket很難做。
但WebSocket的坑在于狀態(tài)管理。HTTP是無狀態(tài)的,請(qǐng)求之間互不認(rèn)識(shí),水平擴(kuò)展隨便加機(jī)器。WebSocket連接是有狀態(tài)的,用戶A連在服務(wù)器1,服務(wù)器2根本不知道這回事。消息要廣播給房間所有人?得引入Redis Pub/Sub或者專門的消息隊(duì)列做跨節(jié)點(diǎn)同步。
心跳機(jī)制也不能省。TCP連接中間經(jīng)過NAT、防火墻,長(zhǎng)時(shí)間沒數(shù)據(jù)會(huì)被靜默斷開。客戶端和服務(wù)端得定期互發(fā)ping/pong,維持連接存活。心跳間隔太短,耗電耗流量;太長(zhǎng),連接斷了用戶還沒感知。
冪等性:為什么刷新頁面不會(huì)重復(fù)下單
冪等性這個(gè)詞很學(xué)術(shù),意思是同樣的操作執(zhí)行N次,結(jié)果和執(zhí)行1次一樣。HTTP方法里,GET天然冪等——你刷新100遍百度首頁,不會(huì)創(chuàng)建100個(gè)搜索任務(wù)。POST默認(rèn)不冪等,同樣參數(shù)發(fā)兩遍,可能創(chuàng)建兩條訂單。
實(shí)際系統(tǒng)中,冪等性靠唯一請(qǐng)求ID保證。客戶端生成全局唯一ID,服務(wù)端用這個(gè)ID去重:處理過了直接返回之前的結(jié)果,沒處理過才執(zhí)行業(yè)務(wù)邏輯。支付場(chǎng)景尤其關(guān)鍵,網(wǎng)絡(luò)抖動(dòng)導(dǎo)致用戶點(diǎn)了兩次"確認(rèn)支付",沒有冪等控制就是雙重扣款。
但冪等性有有效期。請(qǐng)求ID存多久?存太短,用戶隔一小時(shí)重試,當(dāng)成新請(qǐng)求處理;存太長(zhǎng),存儲(chǔ)成本爆炸。通常和業(yè)務(wù)場(chǎng)景綁定:支付相關(guān)存7天,普通操作存1小時(shí),過期后冪等性不再保證。
選型沒有銀彈,只有 trade-off 的清醒認(rèn)知
這篇筆記的價(jià)值,不在于告訴你"該用什么",而在于暴露每個(gè)選項(xiàng)的隱藏成本。長(zhǎng)輪詢省帶寬但吃連接數(shù),水平擴(kuò)展省硬件但增復(fù)雜度,WebSocket實(shí)時(shí)但難運(yùn)維——系統(tǒng)設(shè)計(jì)的本質(zhì),是在約束條件下做取舍。
很多面試題問"如何設(shè)計(jì)一個(gè)秒殺系統(tǒng)",標(biāo)準(zhǔn)答案背得滾瓜爛熟:Redis預(yù)扣庫存、消息隊(duì)列異步下單、限流熔斷兜底。但真到線上,你的團(tuán)隊(duì)能維護(hù)幾級(jí)緩存的一致性?降級(jí)開關(guān)有沒有演練過?全鏈路壓測(cè)的數(shù)據(jù)準(zhǔn)不準(zhǔn)?
架構(gòu)圖上的方框和箭頭是免費(fèi)的,運(yùn)行時(shí)的故障和告警是昂貴的。這篇筆記列出的8個(gè)概念,每個(gè)背后都是生產(chǎn)事故的學(xué)費(fèi)。下次做技術(shù)選型時(shí),不妨多問一句:這個(gè)方案省掉的麻煩,會(huì)在哪里加倍還回來?
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.