1. 程式人生 > >性能測試:聊聊性能優化模式

性能測試:聊聊性能優化模式

工作 矛盾 表現 曲線 代碼復用 dbms 功能實現 累加 緩存

我個人有收藏感興趣的技術鏈接的習慣,最近太忙,沒太多時間看收藏的技術貼,難得今天有空,看了篇美團技術團隊的關於性能優化的內容,

感覺不錯,將其中的一些觀點和方法做了總結歸納,其中還摻雜一些個人的思考,寫下這篇博客,以備日後查閱。。。

原文鏈接:性能優化模式

、性能優化的三個方面

1、降低響應時間

2、提高系統吞吐量

3、提高服務的可用性

三者的關系:在某些場景下互相矛盾,不可兼得

二、性能優化面臨的挑戰

1、日益增長的用戶數量

2、越來越復雜的業務

3、急劇膨脹的數據

三、性能優化的目標

在保持和降低系統99%RT的前提下,不斷提高系統吞吐量,提高流量高峰時期的服務可用性。

四、本文涉及的幾種原則

1、最小可用原則

也稱為快速接入原則,有兩個關註點:

①、快速接入,快速完成;

②、實現核心功能可用;

目標:通過降低開發測試周期,增加試錯機會,快速接入而實現風險可控;

註意:這並不意味著成本的降低,而需要為重構做好準備;

相關閱讀:在產品設計上有一個名詞叫做MVP,即最小可行性產品,這一觀點在《人人都是產品經理1.0紀念版》一書中有相關章節描述。

2、經濟原則

軟件項目生命周期包括:預研、設計、開發、測試、運行、維護等階段。

上面提到的最小可用原則主要運用在預研階段,而經濟原則既可以用在整個軟件生命周期裏,或只關註某一個或者幾個階段;

例如:運行時經濟原則需要考慮的系統成本包括單次請求的CPU、內存、網絡、磁盤消耗等;

設計階段的經濟原則要求避免過度設計;開發階段的經濟原則可能關註代碼復用,工程師資源復用等。

3、代碼復用原則

該原則分兩個層次:

①、使用已有的解決方案或調用已存在的共享庫(Shared Library),也稱為方案復用

②、直接在現有的代碼庫中開發,也稱之為共用代碼庫

方案復用原則出發點就是最大限度地利用手頭已有的解決方案,即使這個方案並不好;方案的形式可以是共享庫,也可以是已存在的服務。

優點:提高生產效率;

類似:方案復用類似於微服務架構(Microservice Architecture),restful風格,設計出可重用性的組件或服務,通過分層組織各層組件來實現良好的架構。

共用代碼庫原則

要求代碼庫中的所有功能編譯時可見,新功能代碼可以無邊界的調用老代碼;另外,原代碼庫已存在的各種運行、編譯、測試、配置環境可復用。

優點:

①、充分利用代碼庫中已有的基礎設施,快速接入新業務;

②、直接調用原代碼中的基礎功能,避免網絡或進程間調用開銷,性能更佳;

類似:共用代碼庫和整體架構(Monolithic Architecture)很接近,它希望盡可能在一套代碼庫中開發,通過直接調用代碼中的基礎功能實現性能優化和快速叠代。

4、奧卡姆剃刀原則

一般情況下,系統的代碼量會隨著功能的增加而變多,健壯性有時候也需要通過編寫異常處理代碼來實現,異常考慮越全面,異常處理的代碼量就越大。

隨著代碼量的增大,引入BUG的概率也越大,系統也就越不健壯。從另一個方面來說,異常流程處理代碼也要考慮健壯性的問題,這就形成了無限循環。

奧卡姆剃刀原則要求

①、一個功能模塊如非必要,就不要;

②、一段代碼如非必寫,則不寫;

區別:最小可用原則主要運用於產品MVP階段,奧卡姆剃刀原則主要指系統設計和代碼編寫兩個方面,這是完全不同的兩個概念;

MVP包含系統設計和代碼編寫,但同時,系統設計和代碼編寫也可以發生在成熟系統的叠代階段。

、性能惡化模式

性能優化的目標之一就是避免系統進入性能惡化模式;

不同性能優化模式可能是避免同一種性能惡化模式;

同一種性能優化模式可能在不同階段避免不同的性能惡化模式;

常見的性能惡化模式

1、長請求擁塞惡化模式

介紹:單次請求時延變長導致系統性能惡化甚至崩潰的模式;

典型場景:復雜的業務場景依賴於多個服務,其中某個服務的響應時間變長,隨之系統整體響應時間變長,進而出現CPU、內存、Swap報警;

具體表現:被依賴服務可用性降低、大量RT變長導致線程堆積、內存使用增加,頻繁GC,RT時間變得更長,最終導致服務徹底崩潰;

表現方式

線程數變多導致縣城之間CPU資源競爭,反過來進一步延長了單次請求時間;

線程數增多及線程中緩存變大,內存消耗加劇,java語言的服務會頻繁的full GC(垃圾回收),導致單次請求時間變得更長;

內存使用變多,使操作系統內存不足,必須使用Swap(內存)交換,可能導致服務崩潰;

惡化流程圖如下

技術分享圖片

2、反復緩存惡化模式

介紹:為降低響應時間,加緩存是種很有效的方式,緩存數據越多,命中率越高,ART就越快;

典型場景:流量高峰沖擊時,系統內存使用增多,出發了JVM進行full GC,進而導致大量緩存被釋放,而大量請求又使得緩存被迅速填滿,

反復緩存導致頻繁的full GC,頻繁的full GC往往導致系統性能急劇惡化;

原因:反復緩存所導致性能惡化的原因是無節制的使用緩存;

指導原則:全局考慮,精細規劃,確保系統完全緩存情況下系統仍然不會頻繁full GC,嚴格控制緩存大小,甚至廢除緩存;

解決措施:線性的增加機器和提高機器的內存大小,可以顯著減少系統崩潰的概率;

惡化流程圖如下:

技術分享圖片

3、多次請求杠桿惡化模式

介紹:客戶端一次點擊往往會出發多次服務端請求,每個服務端請求觸發更多底層服務請求,請求層級越多,杠桿效應越大;

典型場景:多次請求杠桿模式下運行的分布式系統,深層次的服務需處理大量請求,容易成為系統瓶頸;

另外大量請求會給網絡帶來巨大壓力,可能會成為系統徹底崩潰的導火索;

表現方式:性能惡化和流量之間往往遵循指數曲線關系,且線性增加機器解決不了可用性問題;

惡化流程圖如下:

技術分享圖片

六、性能優化模式

1、水平分割模式

動機:典型的服務端流程包含四個環節:接受請求、獲取數據、處理數據、返回結果,大部分耗時長的服務發生在中間兩個環節。

如果服務處理請求采用的是串行調用,那麽其累加效應會極大延長單次請求RT,這就增加了系統進入長請求擁塞惡化模式的概率,進一步的降低系統性能。

如果能對不同的業務請求並行處理,請求總耗時就會大大降低。如下圖所示:

技術分享圖片

Client需要對三個服務進行調用,如果采用順序調用模式,系統的響應時間為18ms,而采用並行調用只需要7ms。

關於client和service之間的連接機制,具體可參考我之前的博客:http連接管理

水平分割模式原理

將整個請求流程切分為必須相互依賴的多個Stage,每個Stage包含相互獨立的多種業務處理。切分之後,水平分割模式串行處理多個Stage,但是在Stage內部並行處理。

一次請求總耗時等於各個Stage耗時總和,每個Stage所耗時間等於該Stage內部最長的業務處理時間。

優化關鍵點:減少Stage數量和降低每個Stage耗時。

優點:

①、降低系統的平均響應時間和TP95響應時間,以及流量高峰時系統崩潰的概率。需要明白的一點:有時候,即使少量的並行化也可以顯著提高整體性能

②、代碼重構比較復雜,但是水平切割模式非常容易理解,只要熟悉系統的業務,識別出可以並行處理的流程,就能夠進行水平切割;

③、對於新系統而言,如果存在可預見的性能問題,把水平分割模式作為一個重要的設計理念將會大大地提高系統的可用性、降低系統的重構風險;

④、有效、容易識別和理解;

2、垂直分割模式

動機:不同業務功能並存於同一個運行系統裏面意味著資源共享,同時也意味著資源使用沖突。

不同業務功能,無論其調用量多小,都有一些內存開銷。對於存在大量緩存的業務功能,數量的增加會極大地提高內存消耗,從而增大系統進入反復緩存反模式的概率。

思路:將系統按照不同的業務功能進行分割,主要有兩種分割模式:部署垂直分割和代碼垂直分割

部署垂直分割:按照可用性要求將系統進行等價分類,不同可用性業務部署在不同機器上,高可用業務單獨部署;

代碼垂直分割:讓不同業務系統不共享代碼,徹底解決系統資源使用沖突問題。

缺點:

①、增加了維護成本。一方面代碼庫數量增多提高了開發工程師的維護成本,另一方面,部署集群的變多會增加運維工程師的工作量;

②、代碼不共享所導致的重復編碼工作。

優點:

①、簡單有效,特別適用於系統已經出現問題而又需要快速解決的場景;

②、部署層次的分割既安全又有效(大部分情況下,即使不增加機器,僅通過部署分割,系統整體吞吐量和可用性都有可能提升);

註意點:對於代碼層次的分割,開發工程師需要在業務承接效率和系統可用性上面做一些折衷考慮。

3、恒變分離模式

原理:基於性能的設計要求變化的數據和不變的數據分開,而在面向對象設計中,為了便於對一個對象有整體的把握,

緊密相關的數據集合往往被組裝進一個類,存儲在一個數據庫表,即使有部分數據冗余。

很多系統的主要工作是處理變化的數據,如果變化的數據和不變的數據被緊密組裝在一起,系統對變化數據的操作將引入額外的開銷。

而如果易變數據占總數據比例非常小,這種額外開銷將會通過杠桿效應惡化系統性能。

分離易變和恒定不變的數據在對象創建、內存管理、網絡傳輸等方面都有助於性能提高。

缺點

①、不符合面向對象的設計原則;

②、增加了類不變量的維護難度;

③、一張數據庫表變成多張,增加維護成本。

恒變分離模式需要滿足兩個條件

①、易變數據占整體數據比例很低(比例越低,杠桿效應越大);

②、易變數據所導致的操作又是系統的主要操作;

分離原則:

對於復雜的業務系統,盡量按照面向對象的原則進行設計,只有在性能出現問題的時候才開始考慮恒變分離模式;

而對於高性能,業務簡單的基礎數據服務,恒變分離模式應該是設計之初的一個重要原則。

4、數據局部性模式

動機:數據局部性模式是多次請求杠桿反模式的針對性解決方案。

典型場景:大數據和強調個性化服務的時代,一個服務消費幾十種不同類型數據的現象非常常見,同時每種類型數據服務都可能需要一個大的集群提供服務。

這就意味著客戶端的一次請求有可能會導致服務端成千上萬次調用操作,很容易使系統進入多次請求杠桿反模式。

數據服務數量暴增的原因:

①、緩存濫用以及缺乏規劃,

②、數據量太大以至於無法在一臺機器上提供全量數據服務,數據局部性模的核心思想是合理組織數據服務,減少服務調用次數。

優化方案:

①、對服務進行重新規劃;

②、對客戶端進行優化,包括:

  本地緩存,對於一致性要求不高且緩存命中率較高的數據服務,本地緩存可以減少服務端調用次數;

  批處理,對於單機或者由等價的機器集群提供的數據服務,盡可能采用批處理方式,將多個請求合成在一個請求中;

  客戶端Hash,對需要通過Hash將請求分配到不同數據服務機器的服務,盡量在客戶端Hash,對於落入同一等價集群的請求采用批處理方式進行調用。

5、實時離線分離模式

該模式的極端要求:離線服務永遠不要調用實時服務,嚴格地講它不是一種系統設計模式,而是一種管理規範。

離線服務和在線服務從可用性、可靠性、一致性的要求上完全不同。

原則上,應該遵循的就是離線服務編程規範,按照在線服務編程規範要求,成本就會大大提高,不符合經濟原則;

從另外一方面講,按照離線服務的需求去寫在線服務代碼,可用性、可靠性、一致性等往往得不到滿足。

具體而言,實時離線分離模式建議如下幾種規範

如果離線程序需要訪問在線服務,應該給離線程序單獨部署一套服務;

類似於MapReduce的雲端多進程離線程序禁止直接訪問在線服務;

分布式系統永遠不要直接寫傳統的DBMS。

優缺點:

需要為在線環境和離線環境單獨部署,維護多套環境所帶來運維成本;

在線環境的數據在離線環境中可能很難獲取;;

BUT:遵從實時離線分離模式是一個非常重要的安全管理準則,任何違背這個準則的行為都意味著系統性安全漏洞,都會增大線上故障概率

6、降級模式

降級模式是系統性能保障的最後一道防線。理論上講,不存在絕對沒有漏洞的系統,或者說,最好的安全措施就是為處於崩潰狀態的系統提供預案。

從系統性能優化的角度來講,不管系統設計地多麽完善,總會有一些意料之外的情況會導致系統性能惡化,最終可能導致崩潰。

對於要求高可用性的服務,在系統設計之初,就必須做好降級設計。

良好的降級方案應該包含如下措施

①、在設計階段,確定系統的開始惡化數值指標(例如:響應時間,內存使用量);

②、當系統開始惡化時,需要第一時間報警;

③、在收到報警後,或者人工手動控制系統進入降級狀態,或者編寫一個智能程序讓系統自動降級;

典型的降級策略有三種:流量降級、效果降級和功能性降級。

流量降級是指當通過主動拒絕處理部分流量的方式讓系統正常服務未降級的流量,這會造成部分用戶服務不可用;

效果降級表現為服務質量的降級,即在流量高峰時期用相對低質量、低延時的服務來替換高質量、高延時的服務,保障所有用戶的服務可用性;

功能性降級也表現為服務質量的降級,指通過減少功能的方式來提高用戶的服務可用性。

區別:效果降級強調的是主功能服務質量的下降,功能性降級更多強調的是輔助性功能的缺失。

優缺點:

在確定使用降級模式的前提下,工程師需要權衡這三種降級策略的利弊;

對於不能接受降級後果的系統,必須要通過其他方式來提高系統的可用性;

總結:降級模式是一種設計安全準則,任何高可用性要求的服務,必須要按照降級模式的準則去設計。

對於處於MVP階段的系統,或者對於可用性要求不高的系統,降級模式並非必須采納的原則。

性能測試:聊聊性能優化模式