資深架構師手把手教你性能優(yōu)化
孔慶龍,一線架構師,具有多年的金融架構經驗,具備 SOA 服務化、服務治理、系統(tǒng)優(yōu)化、分布式系統(tǒng)項目經驗。目前關注于互聯(lián)網(wǎng)金融技術架構設計、分布式架構、微服務架構、DevOps 實踐、大數(shù)據(jù)等領域。
1. 什么是系統(tǒng)優(yōu)化
系統(tǒng)優(yōu)化,一方面是系統(tǒng)化地對 IT 系統(tǒng)或交易鏈上的每個環(huán)節(jié)進行分析并優(yōu)化,另一方面是對單一系統(tǒng)進行瓶頸點分析和優(yōu)化 。這兩方面的優(yōu)化目標大致相同,無非是提高系統(tǒng)的響應速度、吞吐量、降低各層耦合,以靈活應對市場需要。系統(tǒng)優(yōu)化主要在如下三個層面上進行。
-
IT 系統(tǒng)治理層: 這一層面的優(yōu)化不只是性能優(yōu)化,還包括為適應業(yè)務架構變化而帶來的應用架構優(yōu)化(如應用分層、服務治理等)。
-
系統(tǒng)層: 這一層面的優(yōu)化包括業(yè)務流程優(yōu)化、數(shù)據(jù)流程優(yōu)化(如提高系統(tǒng)負載、減少系統(tǒng)開銷等)。
-
基礎設施層: 這一層面的優(yōu)化主要是提高 IaaS 平臺的能力(如使彈性集群具備橫向擴展能力、支持資源快速上下線和轉移等)。
2. 系統(tǒng)優(yōu)化的方法論、思路和原則
什么是方法論,我個人的理解就是聽起來很厲害,做過的人認為是廢話,但可以指明行動方向的理論。 下面就根據(jù)多年經驗,從系統(tǒng)優(yōu)化的 常用方法論 、 優(yōu)化思路 和 優(yōu)化原則 三方面進行簡單分享。
2.1 常用方法論
常用的方法論有以下幾條。
-
阿姆達爾定律(Amdahl Law): 根據(jù)公式 S=1/(1−a+a/n)分析每次對整體效果影響最大的點,并進行優(yōu)化。
-
不訪問不必要的數(shù)據(jù): 減少交易線上的不必要環(huán)節(jié),減少故障點和維護點。
-
就近加載,緩存為王。
-
故障隔離: 不要因為一個系統(tǒng)瓶頸壓垮整個交易平臺。
-
具備良好的擴展能力: 合理地利用資源,提高處理效率并避免單點故障。
-
對交易鏈進行優(yōu)化,提高吞吐量:減少串行同步調用,合理拆分(垂直/水平拆分),規(guī)則前置。
-
性能和功能同等重要: 若交易鏈上有 5 個性能變?yōu)樵O計階段時的 90%,則整體性能會變?yōu)樵O計時的 59%。
2.2 優(yōu)化思路
根據(jù)以往經驗總結出系統(tǒng)優(yōu)化的思路,大致如下:
(1)了解現(xiàn)狀,發(fā)現(xiàn)問題。
(2)確定清晰的優(yōu)化目標,分析現(xiàn)狀與目標的差距并確定執(zhí)行路線。
(3)對系統(tǒng)進行拆分,分別對邏輯層(Web 層、業(yè)務層、持久化層)和物理層(客戶端、網(wǎng)絡、應用服務器、數(shù)據(jù)庫服務器)進行優(yōu)化。
(4)利用工具對系統(tǒng)進行監(jiān)控和測試,并對監(jiān)控和測試結果進行分析。
(5)科學地對系統(tǒng)進行優(yōu)化。
-
遵循一定的程序: 監(jiān)控/性能測試→分析瓶頸→羅列瓶頸的因素→驗證瓶頸因素 →修改系統(tǒng)→確認是否達到優(yōu)化目標。
-
確定影響性能的因素: CPU、內存、I/O、網(wǎng)絡或其他因素。
-
找出主要的瓶頸,優(yōu)先解決關鍵因素,再重復監(jiān)控或測試驗證。
-
避免過度優(yōu)化,一次修改一個瓶頸,不要對不需要的地方進行優(yōu)化。
-
提高 CPU 性能: 寫出更快的代碼,設計出更好的算法,減少短期生存的對象。
-
提高內存性能: 減少長期生存的對象。
-
提高 I/O 性能: 重新設計應用,減少 I/O 的交互。
-
緩存為王: 適度緩存,做到最大化發(fā)揮數(shù)據(jù)庫緩存、應用端緩存、客戶端緩存的作用。
2.3 優(yōu)化原則
系統(tǒng)優(yōu)化的原則如下:
-
在應用系統(tǒng)的設計、開發(fā)過程中,應當始終把性能放在考慮的范圍內。
-
確定清晰明確的性能目標是關鍵。
-
性能優(yōu)化是伴隨整個項目周期的,最好分階段設定目標,在達到預期性能目標之后,即可對本階段工作進行總結和知識轉移,進入下一階段的優(yōu)化工作。
-
必須保證優(yōu)化后的程序可以正確運行。
-
性能更大程度上取決于良好的設計,優(yōu)化技巧只是一個輔助手段。
-
優(yōu)化過程是迭代漸進的過程,每次優(yōu)化的結果都要反饋到后續(xù)的代碼開發(fā)中。
-
性能優(yōu)化不能以犧牲代碼的可讀性和維護性為代價。
3. 性能優(yōu)化
3.1 常見的性能問題
常見的性能問題大多數(shù)是由于資源不足或熱點資源競爭導致的,下面將從客戶端性能、 J2EE 系統(tǒng)性能和數(shù)據(jù)庫性能三方面進行簡單介紹。
常見的客戶端性能問題
常見的客戶端性能問題有如下幾項。
-
加載慢: 第一次啟動慢或者重新加載慢。
-
無響應: 事件突發(fā)導致頁面假死。
-
受網(wǎng)絡帶寬影響嚴重: 因為需要下載大量資源文件,所以在一些網(wǎng)絡環(huán)境不好的地區(qū)頁面加載緩慢。
-
JS(JavaScript)內存溢出: 頻繁地對對象屬性進行操作,造成內存被大量占用,最終溢出。
常見的 J2EE 系統(tǒng)性能問題
常見的 J2EE 系統(tǒng)性能問題有如下幾項。
-
內存泄漏:在運行過程中,內存不斷被占用而不能被回收,內存使用率隨著時間的推移或負載的增加呈線性增長,系統(tǒng)處理效率隨著時間的推移或并發(fā)的增加而下降,直至將分配給 JVM 的內存用盡。
-
資源泄漏:將資源打開后未關閉或未成功關閉而導致的問題。這些資源包括數(shù)據(jù)源連接、文件流等。當這些資源經常被打開而未能成功關閉時,就會導致資源泄漏。數(shù)據(jù)源連接泄漏是常見的資源泄漏問題。
-
過載:過度使用系統(tǒng),超出其所能承受的負荷。
-
資源瓶頸:資源被過度使用或分配不足而引起資源瓶頸問題。
-
線程阻塞、線程死鎖:線程執(zhí)行某段代碼時,無法獲得相關的同步鎖而造成通信阻塞。
-
應用系統(tǒng)響應慢:由于應用算法未優(yōu)化,不合理地讀取大量數(shù)據(jù),SQL 缺少索引或存在過多表關聯(lián)而導致響應時間過長,執(zhí)行變慢。
-
應用系統(tǒng)不穩(wěn)定:應用系統(tǒng)的響應出現(xiàn)時快時慢的現(xiàn)象。
-
應用系統(tǒng)中有各種各樣的異常情況發(fā)生:有些是中間件服務器拋出的異常,有些是數(shù)據(jù)端拋出的異常。
常見的數(shù)據(jù)庫問題
在以往做核心業(yè)務系統(tǒng)技術支持時,遇到的常見的數(shù)據(jù)庫問題如下所述。
-
死鎖:由于聯(lián)機服務過早開啟數(shù)據(jù)庫事務,第三方服務未及時響應,使得鎖和事務無法提交而導致數(shù)據(jù)庫死鎖。
-
I/O 繁忙:由于存在不良 SQL 或業(yè)務邏輯設計不合理而導致大量 I/O 等待。
-
CPU 使用率居高不下:由于高并發(fā)或緩存穿透而導致數(shù)據(jù)庫 CPU 居高不下或忽高忽低。
3.2 性能優(yōu)化的具體工作
“天下武功,唯快不破”,性能優(yōu)化的首要工作就是提高系統(tǒng)的響應時間(響應時間 = 服務處理時間 + 排隊時間)。如圖 16.1 所示的經典響應時間曲線,我們要做的就是通過優(yōu)化程序來減少服務時間,通過提高系統(tǒng)的吞吐量減少系統(tǒng)的排隊時間。圖 16.1 中的縱軸代表的是響應時間,即服務時間和排隊時間的總和; 橫軸代表的是到達率。隨著每單位時間進入系統(tǒng)的事務數(shù)的增加,曲線逐漸向右滑動。隨著到達率的增加,排隊時間會在某一時刻陡然上升,此時,響應時間也將陡然上升,性能下降,而用戶會感到非常沮喪。
圖 16.1
下面通過以往項目中的案例來分析性能優(yōu)化的具體工作。
交易線優(yōu)化
交易線用來從服務消費者的角度查看交易在各個層面上應該完成的功能,以及功能點之間的關系。功能點之間的關系用有向路徑來表示,如圖 16.2 所示。
圖 16.2
交易線優(yōu)化的原則如下:
-
最短路徑: 減少不必要的環(huán)節(jié),避免故障點。
-
交易完整性: 通過沖正或補償交易等確保交易線各環(huán)節(jié)的事物一致性。
-
故障隔離和快速定位: 屏蔽異常情況對正常交易的影響,通過交易碼或錯誤碼快速定位問題。
-
流量控制原則: 可以對服務通道進行流量控制,并結合優(yōu)先級設置優(yōu)先處理級別高的業(yè)務。
-
超時控制漏斗原則: 盡量使交易線上前端系統(tǒng)的超時設置大于后端系統(tǒng)。
-
熔斷和故障隔離原則: 避免由于某個服務提供者出現(xiàn)故障而導致整個交易線不可用。
隨著架構的演變,現(xiàn)在已經由豎井式系統(tǒng)逐步發(fā)展為以服務為單元、可靈活構建的分布式服務體系,如圖 16.3 所示。在服務治理的過程中,原來的核心業(yè)務系統(tǒng)被打碎為各種獨立的業(yè)務組件,一些中間層平臺型系統(tǒng)基于這些業(yè)務組件和流程服務逐漸構建了業(yè)務服務,并為前端應用的快速構建提供業(yè)務支撐。在這個過程中,服務識別和構建是基礎,交易線的規(guī)范是保障,通過交易線規(guī)范可以確定服務治理的涉及范圍,因為在軟件版本迭代時,很少有人能把系統(tǒng)的全部細節(jié)都考慮清楚,所以要靠規(guī)范來確定治理范圍,而不是靠人。
圖 16.3
要開發(fā)一個訂單查詢功能 A,服務整合平臺的 B 和 C 兩個服務都可以完成此功能的開發(fā),不同的是 B 在 C 的基礎上增加了一些額外的校驗。按照最短路徑原則,A 應該直接調 用 C 服務,如圖 16.4 所示。
圖 16.4
流量控制的目的之一是保證各系統(tǒng)健康穩(wěn)定地運行。一般使用計數(shù)器按照交易類型來檢測交易的并發(fā)數(shù),不同交易類型使用不同的計數(shù)器。當交易請求到達時,計數(shù)器加 1; 當請求響應失敗時,計數(shù)器減 1。
流量控制是對服務提供者的一種保護機制,那么服務消費者如何避免因為服務提供者不可用而導致自身不可用,并逐級向交易鏈的調用方放大這種不可用,最終拖垮整個交易鏈路導致雪崩的情況呢? 服務的消費方一般可以通過以下 3 種方式來防止“雪崩”,實現(xiàn)對交易鏈路的保護。
隔離機制:資源池隔離。如果將線程池、數(shù)據(jù)庫連接池等獨立分配,那么即使某類 服務出現(xiàn)問題也只會影響單獨的資源池。
-
熔斷機制: 當調用失敗,觸發(fā)預設的閾值時,應快速返回預設結果,避免大量的同步等待,熔斷偵測請求會定期檢測服務狀態(tài),進行服務狀態(tài)轉換。
-
監(jiān)控報警: 對服務調用狀態(tài)進行監(jiān)控并設置預警值,在發(fā)生異常時可以及時通知相關人員進行干預處理,縮短異常影響范圍。
客戶端優(yōu)化
圖 16. 5
從 Web 請求時序(如圖 16.5 所示)中可以看出,客戶端優(yōu)化的首要目標是加快頁面展 現(xiàn)和響應速度,其次是減少對服務器端的調用,常見的解決辦法如下:
-
分析瓶頸點,有針對性地進行優(yōu)化。
-
緩存為王,通過在客戶端緩存靜態(tài)數(shù)據(jù)提升頁面響應時間。
-
通過 gzip、deflate 壓縮來減少客戶端網(wǎng)絡的下載流量。執(zhí)行壓縮的好處是可以減少 60%左右的文本類文件所占用的空間,但執(zhí)行時需要注意解析 HTTP 請求的, Accept-Encoding 頭判斷是否支持壓縮,并在響應中設置 Content-Encoding 編碼格式。
-
使用壓縮工具對 JS 進行壓縮,減小 JS 文件所占用的空間。
-
刪除、合并腳本、樣式表及圖片,減少 GET 請求。*無阻塞加載 JS。
-
預加載圖片、CSS 樣式、JS 腳本。
-
按需加載 JS 腳本。
-
優(yōu)化 JS 處理方法,提升頁面處理速度。
圖 16.6 所示的是某企業(yè)內部應用系統(tǒng)客戶端的 HTTP 請求監(jiān)控記錄。
圖 16.6
從圖 16.6 中可以看到共計發(fā)送 25 次請求(21 次命中緩存、4 次與服務器端交互)。從 圖 16.7 所示的統(tǒng)計信息中可以看到: 請求耗時總計 5.645s,進行了 4 次網(wǎng)絡交互,接收到 5.9KB 數(shù)據(jù),發(fā)送了 110.25KB 數(shù)據(jù),使用 gzip 壓縮節(jié)省了 8KB 數(shù)據(jù)。
圖 16.7
通過優(yōu)化后端請求、合并和壓縮 JS/JSP 文件等操作,將頁面響應時間優(yōu)化到 2s 左右。
進行前端優(yōu)化最好了解瀏覽器原理、HTTP 原理。
服務器端優(yōu)化
服務器端的涉及面比較廣,圖 16.8 整理了在進行服務器端優(yōu)化時可能存在的問題,以及所采用的輔助分析工具、分析思路、常見解決辦法。
圖 16.8