大型網(wǎng)站系統(tǒng)優(yōu)化方案
時(shí)間:2023-04-18 22:20:01 | 來源:網(wǎng)站運(yùn)營
時(shí)間:2023-04-18 22:20:01 來源:網(wǎng)站運(yùn)營
大型網(wǎng)站系統(tǒng)優(yōu)化方案:
前言
系統(tǒng)優(yōu)化的三個(gè)基本方向:性能(Performance)、穩(wěn)定性(Stability)、可維護(hù)性(Maintainability)。三者之間并不是完全獨(dú)立的,而是存在著復(fù)雜的相互作用關(guān)系,有時(shí)甚至?xí)讼碎L。
最優(yōu)秀的軟件系統(tǒng),并非要把這三個(gè)方向都做到極致,而是會(huì)根據(jù)自己實(shí)際的業(yè)務(wù)需求和場景合理取舍,在這三者之間達(dá)到一個(gè)綜合最優(yōu)的動(dòng)態(tài)平衡狀態(tài),讓各方面都能做到足夠好即可。
所以,優(yōu)化不只是一門科學(xué),也是一門藝術(shù)。
服務(wù)器配置
服務(wù)器4臺(tái)cpu:2Cmemory:2G帶寬
性能指標(biāo):
1.吞吐率(Throughput):系統(tǒng)單位時(shí)間內(nèi)能處理的工作負(fù)載,例如:在線 Web 系統(tǒng) - QPS/TPS,離線數(shù)據(jù)分析系統(tǒng) - 每秒處理的數(shù)據(jù)量。2.響應(yīng)時(shí)間(Response Time):以 Web 請(qǐng)求處理為例,響應(yīng)時(shí)間(RT)即請(qǐng)求從發(fā)出到收到的往返時(shí)間,一般會(huì)由網(wǎng)絡(luò)傳輸延遲、排隊(duì)延遲和實(shí)際處理耗時(shí)幾個(gè)部分共同組成。3.可伸縮性(Scalability):系統(tǒng)通過增加機(jī)器資源(垂直/水平)來承載更多工作負(fù)載的能力;投入產(chǎn)出比越高(理想情況是線性伸縮),則說明系統(tǒng)的可伸縮性越好。
此外,同一個(gè)系統(tǒng)的吞吐率與響應(yīng)時(shí)間,一般還會(huì)存在如下關(guān)聯(lián)關(guān)系:吞吐率小于某個(gè)臨界值時(shí),響應(yīng)時(shí)間幾乎不變;一旦超出這個(gè)臨界值,系統(tǒng)將進(jìn)入超載狀態(tài)(overloaded),響應(yīng)時(shí)間開始線性增長。對(duì)于一個(gè)有穩(wěn)定性要求的系統(tǒng),需要在做性能壓測和容量規(guī)劃時(shí)充分考慮這個(gè)臨界值的大小。
注:其實(shí)按更嚴(yán)謹(jǐn)?shù)恼f法,性能就是單指一個(gè)系統(tǒng)有多“快”;上述部分指標(biāo)并不純粹只代表系統(tǒng)快慢,但也都與快慢息息相關(guān)。
性能分析
- 定位性能瓶頸
CPU bound vs I/O bound - 工具
- 系統(tǒng):tsar、top、iostat、vmstat
- 網(wǎng)絡(luò):iftop、tcpdump、wireshark
- 數(shù)據(jù)庫:SQL explain、CloudDBA
- 應(yīng)用代碼:JProfiler、Arthas、jstack
性能優(yōu)化:(優(yōu)化做的越多,往往可維護(hù)性就會(huì)變差)
1)簡化(有些事,你可以選擇不做)
業(yè)務(wù)層面:流程精簡、需求簡化。
編碼層面:循環(huán)內(nèi)減少高開銷操作、編寫更少的代碼。
架構(gòu)層面:減少?zèng)]必要的抽象/分層。
數(shù)據(jù)層面:數(shù)據(jù)清洗、提取、聚合。
2)并行(有些事,你可以找人一起做)
方式:單機(jī)并行(多線程)、多機(jī)并行(分布式)。
優(yōu)點(diǎn):充分利用機(jī)器資源(多核、集群)。
缺點(diǎn):同步開銷、線程開銷、數(shù)據(jù)傾斜
- 同步優(yōu)化:樂觀鎖、細(xì)粒度鎖、無鎖
- 線程替代(如協(xié)程:Java WISP、Go routines、Kotlin coroutines)。
- 數(shù)據(jù)傾斜:負(fù)裁均衡(Hash/RR/動(dòng)態(tài)).
3)異步(有些事,你可以放手,不用死等)
方式:消息隊(duì)列+任務(wù)線程+通知機(jī)制。
優(yōu)點(diǎn):提升吞吐率、組件解耦、削峰填谷
缺點(diǎn):排隊(duì)延遲(隊(duì)列積壓)。
- 避免過度積壓:Back-pressure(Reactive思想)
4)批量(有些事,你可以合起來一起做)
方式:多次單一操作 ---> 合并為單次批量操作。
案例:TCP Nagel算法;DB的批量讀寫接口。
優(yōu)點(diǎn):避免單次操作的固有開銷,均攤后總開銷更低。
缺點(diǎn):等待延遲+聚合延遲。
- 減少等待延遲:Timeout觸發(fā)提交,控制延遲上限。
5)時(shí)間空間互換(游戲的本質(zhì):要么有閑,要么有錢)
空間換時(shí)間:避免重復(fù)計(jì)算、拉近傳輸距離、分流減少壓力。
時(shí)間換空間:有時(shí)候也能達(dá)到“更快”的效果(數(shù)據(jù)量減少--->傳輸時(shí)間減少)
- 案例: 數(shù)據(jù)壓縮(HTTP/2 頭部壓縮、Bitmap)
6)數(shù)據(jù)結(jié)構(gòu)與算法優(yōu)化(程序=數(shù)據(jù)結(jié)構(gòu)+算法)
- 多了解一些“冷門”的數(shù)據(jù)結(jié)構(gòu):Skip list、Bloom filter、Time Wheel等
- 一些簡單的算法思想:遞歸、分治、貪心、動(dòng)態(tài)規(guī)劃。
7)池化&局部化(共享經(jīng)濟(jì)與小區(qū)超市)
池化(Pooling):減少資源創(chuàng)建和銷毀開銷。
- 案例:線程池、內(nèi)存池、DB連接池、Socket連接池。
局部化(Localization) 避免共享資源競爭開銷。
- 案例:TLB(ThreadLocalBuffer)、多級(jí)緩存(本地局部緩存--->共享全局緩存)。
8)更多優(yōu)化手段
- 升級(jí)紅利:內(nèi)核、內(nèi)存、JRE、依賴庫、協(xié)議、硬盤(SSD)。
- 調(diào)參大師:配置、JVM、內(nèi)核、網(wǎng)卡。
- SQL優(yōu)化:索引、select *、LIMIT 1。
- 業(yè)務(wù)特征定制優(yōu)化:凌晨業(yè)務(wù)低峰期做日志輪轉(zhuǎn)。
- Hybrid思想(優(yōu)點(diǎn)結(jié)合):JDK sort()實(shí)現(xiàn)、Weex/RN
穩(wěn)定性優(yōu)化
穩(wěn)定是相對(duì)的,業(yè)務(wù)規(guī)模越大、場景越復(fù)雜、系統(tǒng)越容易出現(xiàn)不穩(wěn)定,且?guī)淼挠绊懸苍絿?yán)重。
衡量指標(biāo)
不同業(yè)務(wù)所提供的服務(wù)類型千差萬別,如何用一致的指標(biāo)去衡量系統(tǒng)穩(wěn)定性?標(biāo)準(zhǔn)做法是定義服務(wù)的可用性(Availability):只要對(duì)用戶而言服務(wù)“可用”,那就認(rèn)為系統(tǒng)當(dāng)前是穩(wěn)定的;否則就是不穩(wěn)定。用這樣的方式,采集和匯總后就能得到服務(wù)總的可用/不可用比例(服務(wù)時(shí)長 or 服務(wù)次數(shù)),以此來監(jiān)測和量化一個(gè)系統(tǒng)的穩(wěn)定性。
可是,通過什么來定義某個(gè)服務(wù)當(dāng)前是否可用呢?這一點(diǎn)確實(shí)跟業(yè)務(wù)相關(guān),但大部分同類業(yè)務(wù)都可以用類似的方式去定義。例如,對(duì)于一般的 Web 網(wǎng)站,我們可以按如下方式去定義服務(wù)是否可用:API 請(qǐng)求都返回成功,且頁面總加載時(shí)間 < 3 秒。
對(duì)于阿里云對(duì)外提供的云產(chǎn)品而言,服務(wù)可用性是一個(gè)更加需要格外重視并持續(xù)提升的指標(biāo):阿里云上的很多用戶會(huì)同時(shí)使用多款云產(chǎn)品,其中任何一款產(chǎn)品出現(xiàn)可用性問題,都會(huì)直接被用戶的用戶感知和放大。所以,越是底層的基礎(chǔ)設(shè)施,可用性要求就越高。關(guān)于可用性的更多細(xì)節(jié)指標(biāo)和概念(SLI / SLO / SLA),可進(jìn)一步參考云智能 SLA 了解。
可用性測量
1)探針模擬
從客戶端側(cè),模擬用戶的調(diào)用行為。
優(yōu)點(diǎn):數(shù)據(jù)真實(shí)(客戶端角度)
缺點(diǎn):數(shù)據(jù)不全面(單一客戶數(shù)據(jù))
2)服務(wù)端采集
從服務(wù)端側(cè),直接分析日志和數(shù)據(jù)。
優(yōu)點(diǎn):覆蓋所有調(diào)用數(shù)據(jù)。
缺點(diǎn):缺失客戶端鏈路數(shù)據(jù)。
優(yōu)化原則
你應(yīng)該做的:關(guān)注 RT 的數(shù)據(jù)分布(如:p50/p99/p999 分位點(diǎn)),而不是平均值(mean) —— 平均值并沒有太大意義,更應(yīng)該去關(guān)注你那 1%、0.1% 用戶的準(zhǔn)確感受。
你不應(yīng)該做的:不要嘗試承諾和優(yōu)化可用性到 100% —— 一方面是無法實(shí)現(xiàn),存在太多客觀不可控因素;另一方面也沒有意義,客戶幾乎關(guān)注不到 0.001% 的可用性差別。
優(yōu)化手段
常用的穩(wěn)定性優(yōu)化手段有哪些?這里也總結(jié)了 8 個(gè)套路:
1)避免單點(diǎn) 如何避免?
集群部署
數(shù)據(jù)副本
多機(jī)房容災(zāi)
只堆量不夠,還需要具備故障轉(zhuǎn)移能力(Failover)。
接入層:DNS、VipServer、SLB。
服務(wù)層:服務(wù)發(fā)現(xiàn) + 健康檢查 + 剔除機(jī)制。
應(yīng)用層:無狀態(tài)設(shè)計(jì)(Stateless),便于隨時(shí)和快速切換。
2)流控/限流
- 類型:QPS 流控、并發(fā)度流控。
- 工具:RateLimiter、信號(hào)量、Sentinel。
- 粒度:全局、用戶級(jí)、接口級(jí)。
- 熱點(diǎn)流控:避免意料之外的突增流量。
3)熔斷
目的:防止連鎖故障(雪崩效應(yīng))。
工具:Hystrix、Failsafe、Resilience4j。
功能:自動(dòng)繞開異常服務(wù)并檢測恢復(fù)狀態(tài)。
流程:關(guān)閉 → 打開 → 半開。
4)降級(jí)
觸發(fā)原因:流控、熔斷、負(fù)載過高。
常見降級(jí)方式:
關(guān)閉非核心功能:停止應(yīng)用日志打印
犧牲數(shù)據(jù)時(shí)效性:返回緩存中舊數(shù)據(jù)
犧牲數(shù)據(jù)精確性:降低數(shù)據(jù)采樣頻率
5)超時(shí)/重試
超時(shí):避免調(diào)用端陷入永久阻塞。
超時(shí)時(shí)間設(shè)置:全鏈路自上而下規(guī)劃
Timeout vs. Deadline:使用絕對(duì)時(shí)間會(huì)更好
重試:確??芍卦嚥僮鞯膬绲刃浴?br>
消息去重
異步重試
指數(shù)退避
6)資源設(shè)限
目的:防止資源被異常流量耗盡
資源類型:線程、隊(duì)列、DB 連接
設(shè)限方式:資源池化、有界隊(duì)列
超限處理:返回 ServiceUnavailable / QuotaExceeded
7)資源隔離
目的:防止資源被部分異常流量耗盡;為 VIP 客戶提供服務(wù)質(zhì)量保證(QoS)。
隔離方式:隊(duì)列劃分、獨(dú)立集群;注意處理優(yōu)先級(jí)和資源分配比例。
8 )安全生產(chǎn) 程序動(dòng)態(tài)性:開關(guān)、配置、熱升級(jí)。
Switch:類型安全;侵入性小。
審核機(jī)制:代碼 Review、發(fā)布審批。
灰度發(fā)布;分批部署;回滾預(yù)案。
DUCT:自動(dòng)/手動(dòng)調(diào)整 HSF 節(jié)點(diǎn)權(quán)重。
可維護(hù)性優(yōu)化
維護(hù)的英文是 maintain,也能翻譯成:維持、供給。所以軟件維護(hù)能有多重要?它就是軟件系統(tǒng)的呼吸機(jī)和食物管道,維持軟件生命的必要供給。
系統(tǒng)開發(fā)完成上線,不過只是把它“生”下來而已。軟件真正能發(fā)揮多大價(jià)值,看的是交付后持續(xù)的價(jià)值兌現(xiàn)過程 —— 是不斷茁壯成長,為用戶發(fā)光發(fā)熱?還是慢慢墮落,逐漸被用戶所遺忘?這并不是取決于它當(dāng)下瞬時(shí)是否足夠優(yōu)秀(性能)和靠譜(穩(wěn)定),而是取決于未來 —— 能否在不斷變化的市場環(huán)境、客戶需求和人為因素中,始終保持足夠優(yōu)秀和靠譜,并且能越來越好。
相比性能和穩(wěn)定性而言,可維護(hù)性所體現(xiàn)的價(jià)值往往是最長遠(yuǎn)、但也最難在短期內(nèi)可兌現(xiàn)的,因此很多軟件項(xiàng)目都選擇了在前期犧牲可維護(hù)性。這樣決策帶來的后果,就跟架構(gòu)設(shè)計(jì)一樣,是幾乎無法(或者需要非常高的成本)去彌補(bǔ)和挽回的。太多的軟件項(xiàng)目,就是因?yàn)樵絹碓讲豢删S護(hù)(代碼改不動(dòng)、bug 修不完、feature 加不上),最后只能慢慢淪落為一個(gè)誰都不想碰的遺留項(xiàng)目。
衡量指標(biāo)
相比性能和穩(wěn)定性而言,可維護(hù)性確實(shí)不太好量化(藝術(shù)成分 > 科學(xué)成分)。這里我選取了幾個(gè)偏定性分析的指標(biāo):
1)復(fù)雜度(Complexity):是否復(fù)雜度可控?
編碼:簡潔度、命名一致性、代碼行數(shù)等。
架構(gòu):組件耦合度、層次清晰度、職責(zé)單一性等。
2)可擴(kuò)展性(Extensibility):是否易于變更?
需要變更代碼或配置時(shí),是否簡單優(yōu)雅、不易出錯(cuò)。
3)可運(yùn)維性(Operability):是否方便運(yùn)維?
日志、監(jiān)控是否完善;部署、擴(kuò)容是否容易。
重要性
軟件生命周期:維護(hù)周期 >> 開發(fā)周期。
破窗效應(yīng)、熵增定律:可維護(hù)性會(huì)趨向于越來越差。
遺留系統(tǒng)的危害:理解難度,修改成本,變更風(fēng)險(xiǎn);陷入不斷踩坑、填坑、又挖坑的循環(huán)。
優(yōu)化原則
你應(yīng)該做的:遵循 KISS 原則、DRY 原則、各種代碼可讀性和架構(gòu)設(shè)計(jì)原則等。
你不應(yīng)該做的:引入過多臨時(shí)性、Hack 代碼;功能 Work 就 OK,欠一堆技術(shù)債(出來混總是要還的)。
優(yōu)化手段
常用的可維護(hù)性優(yōu)化手段有哪些?這里我總結(jié)了 4 個(gè)套路:
1)編碼規(guī)范
編碼:推薦《Java 開發(fā)手冊(cè)》
日志:無盲點(diǎn)、無冗余、TraceID。
測試:代碼覆蓋度、自動(dòng)化回歸。
2)代碼重構(gòu)
何時(shí)重構(gòu):任何時(shí)候代碼中嗅到壞味道(bad smell)。
重構(gòu)節(jié)奏:小步迭代、回歸驗(yàn)證。
重構(gòu) vs. 重寫:需要綜合考慮成本、風(fēng)險(xiǎn)、并行版本維護(hù)等因素。
3)數(shù)據(jù)驅(qū)動(dòng)
系統(tǒng)數(shù)據(jù):監(jiān)控覆蓋、Metrics采集等,對(duì)于理解系統(tǒng)、排查問題至關(guān)重要。
業(yè)務(wù)數(shù)據(jù):一致性校驗(yàn)、舊數(shù)據(jù)清理等;要相信,數(shù)據(jù)往往比代碼要活得更久。
4)技術(shù)演進(jìn) 死守陣地 or 緊跟潮流? 需要綜合評(píng)估風(fēng)險(xiǎn)、生產(chǎn)力、學(xué)習(xí)成本。
當(dāng)前方向:微服務(wù)化、容器化。