【技術架構—要點】高性能架構

性能是客觀的指標,能夠具體到響應時間、吞吐量等技術指標,同時也是主觀的感覺,用戶的感覺和工程師的感覺不一樣,不一樣的用戶感覺也不一樣。前端

性能測試

性能測試指標

不一樣視角下有不一樣的性能標準,不一樣的標準有不一樣的性能測試指標,經常使用的指標有以下幾個:算法

  • 響應時間:指應用執行一個操做須要的時間,包括從發出請求開始到收到最後響應數據所須要的時間。響應時間是系統最重要的性能指標,直觀地反映了系統的「快慢」。
  • 併發數:指系統可以同時處理請求的數目,這個數字也反映了系統的負載特性。
  • 吞吐量:指單位時間內系統處理的請求數量,體現系統的總體處理能力。

性能測試方法

性能測試具體可細分爲性能測試、負載測試、壓力測試、穩定性測試。數據庫

性能測試是一個不斷對系統增長訪問壓力,以得到系統性能指標、最大負載能力的過程。所謂的增長訪問壓力,在系統測試環境中,就是不斷增長測試程序的併發請求數,通常說來,性能測試遵循如圖所示的拋物線規律。編程

image.png

在開始階段,隨着併發請求數目的增長,系統使用較少的資源就達到較好的處理能力(a~b段),這一段是網站的平常運行區間,網站的絕大部分訪問負載壓力都集中在這一段區間,被稱做性能測試,測試目標是評估系統性能是否符合需求及設計目標。segmentfault

隨着壓力的持續增長,系統處理能力增長變緩,直到達到一個最大值(c點),這是系統的最大負載點,這一段被稱做負載測試。測試目標是評估當系統由於突發事件超出平常訪問壓力的狀況下,保證系統正常運行狀況下可以承受的最大訪問負載壓力。設計模式

超過這個點後,再增長壓力,系統的處理能力反而降低,而資源消耗卻更多,直到資源消耗達到極限(d點),這個點能夠看做是系統的崩潰點,超過這個點繼續加大併發請求數目,系統不能再處理任何請求,這一段被稱做壓力測試,測試目標是評估可能致使系統崩潰的最大訪問負載壓力。瀏覽器

性能優化策略

若是系統存在性能問題,必須對請求經歷的各個環節進行分析,排查可能出現性能瓶頸的地方,定位問題。緩存

排查一個網站的性能瓶頸和排查一個程序的性能瓶頸的手法基本相同:檢查請求處理的各個環節的日誌,分析哪一個環節響應時間不合理、超過預期;而後檢查監控數據,分析影響性能的主要因素是內存、磁盤、網絡、仍是CPU,是代碼問題仍是架構設計不合理,或者系統資源確實不足。安全

定位產生性能問題的具體緣由後,就須要進行性能優化,根據網站分層架構,可分爲Web前端性能優化、應用服務器性能優化、存儲服務器性能優化3大類。性能優化

Web前端性能優化

通常說來Web前端指網站業務邏輯以前的部分,包括瀏覽器加載、網站視圖模型、圖片服務、CDN服務等,主要優化手段有優化瀏覽器訪問、使用反向代理、CDN等。

瀏覽器訪問優化

減小http請求

HTTP協議是無狀態的應用層協議,意味着每次HTTP請求都須要創建通訊鏈路、進行數據傳輸,而在服務器端,每一個HTTP都須要啓動獨立的線程去處理。這些通訊和服務的開銷都很昂貴,減小HTTP請求的數目可有效提升訪問性能。

減小HTTP的主要手段是合併CSS、合併JavaScript、合併圖片。將瀏覽器一次訪問須要的JavaScript、CSS合併成一個文件,這樣瀏覽器就只須要一次請求。圖片也能夠合併,多張圖片合併成一張,若是每張圖片都有不一樣的超連接,可經過CSS偏移響應鼠標點擊操做,構造不一樣的URL。

使用瀏覽器緩存

對一個網站而言,CSS、JavaScript、Logo、圖標這些靜態資源文件更新的頻率都比較低,若是將這些文件緩存在瀏覽器中,能夠極好地改善性能。經過設置HTTP頭中Cache-Control和Expires的屬性,可設定是否開啓瀏覽器緩存以及緩存時間。

靜態資源文件變化須要及時應用到客戶端瀏覽器,這種狀況,可經過改變文件名實現,即生成一個新的JS文件並更新HTML文件中的引用。在更新靜態資源時,應採用批量更新的方法,並有必定的間隔時間,以避免用戶瀏覽器忽然大量緩存失效,集中更新緩存,形成服務器負載驟增、網絡擁塞的狀況。

啓用壓縮

在服務器端對文件進行壓縮,在瀏覽器端對文件解壓縮,可有效減小通訊傳輸的數據量。可是壓縮對服務器和瀏覽器產生必定的壓力,在通訊帶寬良好,而服務器資源不足的狀況下要權衡考慮

減小Cookie傳輸

一方面,Cookie包含在每次請求和響應中,太大的Cookie會嚴重影響數據傳輸,所以哪些數據須要寫入Cookie須要慎重考慮,儘可能減小Cookie中傳輸的數據量。

另外一方面,對於某些靜態資源的訪問,如CSS、Script等,發送Cookie沒有意義,能夠考慮靜態資源使用獨立域名訪問,避免請求靜態資源時發送Cookie,減小Cookie傳輸的次數。

CDN加速

CDN(Content Distribute Network,內容分發網絡)的本質仍然是一個緩存,並且將數據緩存在離用戶最近的地方,使用戶以最快速度獲取數據。

因爲CDN部署在網絡運營商的機房,這些運營商又是終端用戶的網絡服務提供商,所以用戶請求路由的第一跳就到達了CDN服務器,當CDN中存在瀏覽器請求的資源時,從CDN直接返回給瀏覽器,加快用戶訪問速度,減小數據中心負載壓力。

反向代理

反向代理服務器位於網站機房一側,代理網站Web服務器接收HTTP請求。反向代理服務器具備保護網站安全的做用,除了安全功能,代理服務器也能夠經過配置緩存功能加速Web請求。

當用戶第一次訪問靜態內容的時候,靜態內容就被緩存在反向代理服務器上,這樣當其餘用戶訪問該靜態內容的時候,就能夠直接從反向代理服務器返回,加速Web請求響應速度。有些網站會把某些熱門的動態內容也緩存在代理服務器上,當這些動態內容有變化時,經過內部通知機制通知反向代理緩存失效,反向代理會從新加載最新的動態內容再次緩存起來。

此外,反向代理也能夠實現負載均衡的功能,進而改善網站高併發狀況下的性能。

應用服務器性能優化

應用服務器就是處理網站業務的服務器,網站的業務代碼都部署在這裏,優化手段主要有緩存、集羣、異步等。

緩存

性能優化第必定律:優先考慮使用緩存優化性能。緩存指將數據存儲在相對較高訪問速度的存儲介質中,以供系統處理。

使用策略

使用緩存的首要前提就是存在熱點數據,若是不存在熱點訪問,那麼會出現大部分數據尚未被再次訪問就被擠出緩存。並且須要緩存的數據讀寫比必須足夠高,數據的讀寫比至少應該在2:1以上,緩存纔有意義。

數據不一致

通常會對緩存的數據設置失效時間,一旦超過失效時間,就要從數據庫中從新加載。所以應用要容忍必定時間的數據不一致。在互聯網應用中,這種延遲一般是能夠接受的,可是具體應用仍需慎重對待。還有一種策略是數據更新時當即更新緩存,不過這也會帶來更多系統開銷和事務一致性的問題。

緩存預熱

新啓動的緩存系統若是沒有任何數據,在構建緩存數據的過程當中,系統的性能和數據庫負載都不太好,那麼最好在緩存系統啓動時就把熱點數據加載好,這個緩存預加載手段叫做緩存預熱。

緩存可用性

隨着業務的發展,緩存會承擔大部分數據訪問的壓力,當緩存服務崩潰時,數據庫會由於徹底不能承受如此大的壓力而宕機,進而致使整個網站不可用。

經過分佈式緩存服務器集羣,將緩存數據分佈到集羣多臺服務器上可在必定程度上改善緩存的可用性。當一臺緩存服務器宕機的時候,只有部分緩存數據丟失,從新從數據庫加載這部分數據不會對數據庫產生很大影響。

緩存穿透

若是由於不恰當的業務、或者惡意攻擊持續高併發地請求某個不存在的數據,因爲緩存沒有保存該數據,全部的請求都會落到數據庫上,會對數據庫形成很大壓力,甚至崩潰。一個簡單的對策是將不存在的數據(null)也緩存起來,亦或是使用布隆過濾器。

異步

使用消息隊列將調用異步化,可改善系統的擴展性,同時也能夠改善系統性能。因爲消息隊列服務器處理速度遠快於數據庫(消息隊列服務器也比數據庫具備更好的伸縮性),用戶的響應延遲可獲得有效改善,而且能夠下降數據庫的負載壓力。

消息隊列具備很好的削峯做用——即經過異步處理,將短期高併發產生的事務消息存儲在消息隊列中,從而削平高峯期的併發事務。在電子商務網站促銷活動中,合理使用消息隊列,可有效抵禦促銷活動剛開始大量涌入的訂單對系統形成的衝擊。

須要注意的是,因爲數據寫入消息隊列後當即返回給用戶,數據在後續的業務校驗、寫數據庫等操做可能失敗,所以在使用消息隊列進行業務異步處理後,須要適當修改業務流程進行配合。如訂單提交後,訂單數據寫入消息隊列,不能當即返回用戶訂單提交成功,須要在消息隊列的訂單消費者進程真正處理完該訂單,甚至商品出庫後,再經過電子郵件或SMS消息通知用戶訂單成功,以避免交易糾紛。

注:任何能夠晚點作的事情都應該晚點再作。

集羣

在高併發訪問的場景下,使用負載均衡技術爲一個應用構建一個由多臺服務器組成的服務器集羣,將併發訪問請求分發到多臺服務器上處理,避免單一服務器因負載壓力過大而響應緩慢,使用戶請求具備更好的響應延遲特性。

代碼優化

理優化業務代碼,能夠很好地改善系統性能。代碼優化手段有不少,這裏咱們概要地關注比較重要的幾個方面。

多線程

多用戶併發訪問是應用系統的基本需求,大型網站的併發用戶數會達到數萬,單臺服務器的併發用戶也會達到數百。從資源利用的角度看,使用多線程的緣由主要有兩個:IO阻塞與多CPU。

網站的應用程序通常都被Web服務器容器管理,用戶請求的多線程也一般被Web服務器容器管理,但無論是Web容器管理的線程,仍是應用程序本身建立的線程,一臺服務器上啓動多少線程合適呢?假設服務器上執行的都是相同類型任務,針對該類任務啓動的線程數有個簡化的估算公式可供參考:啓動線程數 = [任務執行時間 /(任務執行時間-IO等待時間)] × CPU內核數。

多線程編程一個須要注意的問題是線程安全問題,也即同步問題。解決線程安全的主要手段有使用無狀態對象和局部對象(不共享數據)以及使用鎖等。

資源複用

系統運行時,要儘可能減小那些開銷很大的系統資源的建立和銷燬,好比數據庫鏈接、網絡通訊鏈接、線程、複雜對象等。從編程角度,資源複用主要有兩種模式:單例(Singleton)和對象池(ObjectPool)。

單例雖然是GoF經典設計模式中被較多詬病的一個模式,但因爲目前Web開發中主要使用貧血模式,從Service到Dao都是無狀態對象,無需重複建立,這種狀況下使用單例模式也就很天然了。

對象池模式經過複用對象實例,減小對象建立和資源消耗。所謂的鏈接池、線程池,本質上都是對象池,池管理方式也基本相同。

垃圾回收

如今的主力編程語言如Java、PHP、Golang等都具備自動垃圾回收功能,垃圾回收可能會對系統的性能特性產生巨大影響。理解所使用的編程語言的垃圾回收機制有助於程序優化和參數調優,以及編寫內存安全的代碼。

存儲性能優化

在應用系統中,海量的數據讀寫對磁盤訪問形成巨大壓力,雖然能夠經過Cache解決一部分數據讀壓力,可是磁盤仍然是系統最嚴重的瓶頸。

機械硬盤和固態硬盤

機械硬盤是目前最經常使用的一種硬盤,經過馬達驅動磁頭臂,帶動磁頭到指定的磁盤位置訪問數據。機械硬盤在數據連續訪問和隨機訪問時,性能差異很是大。

固態硬盤沒有機械裝置,數據存儲在可持久記憶的硅晶體上,所以能夠像內存同樣快速隨機訪問。在應用系統中,大部分數據訪問都是隨機的,這種狀況下SSD具備更好的性能表現。

B+樹和LSM樹

爲了改善數據訪問特性,文件系統或數據庫系統一般會對數據排序後存儲,加快數據檢索速度,這就須要保證數據在不斷更新、插入、刪除後依然有序,傳統關係數據庫的作法是使用B+樹,如圖所示。

image.png

B+樹是一種專門針對磁盤存儲而優化的N叉排序樹,以樹節點爲單位存儲在磁盤中,從根開始查找所需數據所在的節點編號和磁盤位置,將其加載到內存中而後繼續查找,直到找到所需的數據。

目前許多NoSQL產品採用LSM樹做爲主要數據結構,如圖所示。

image.png

LSM樹能夠看做是一個N階合併樹。數據寫操做都在內存中進行,而且都會建立一個新記錄(修改會記錄新的數據值,而刪除會記錄一個刪除標誌),這些數據在內存中仍然仍是一棵排序樹,當數據量超過設定的內存閾值後,會將這棵排序樹和磁盤上最新的排序樹合併。當這棵排序樹的數據量也超過設定閾值後,和磁盤上下一級的排序樹合併。合併過程當中,會用最新更新的數據覆蓋舊的數據(或者記錄爲不一樣版本)。

在須要進行讀操做時,老是從內存中的排序樹開始搜索,若是沒有找到,就從磁盤上的排序樹順序查找。

在LSM樹上進行一次數據更新不須要磁盤訪問,在內存便可完成,速度遠快於B+樹。當數據訪問以寫操做爲主,而讀操做則集中在最近寫入的數據上時,使用LSM樹能夠極大程度地減小磁盤的訪問次數,加快訪問速度。

延伸閱讀:【分佈式—基礎】數據存儲與檢索

RAID

RAID(廉價磁盤冗餘陣列)技術主要是爲了改善磁盤的訪問延遲,加強磁盤的可用性和容錯能力。目前服務器級別的計算機都支持插入多塊磁盤,經過使用RAID技術,實現數據在多塊磁盤上的併發讀寫和數據備份。經常使用RAID技術有如下幾種,如圖所示。

image.png

RAID 0

數據在從內存緩衝區寫入磁盤時,根據磁盤數量將數據分紅N份,這些數據同時併發寫入N塊磁盤,使得數據總體寫入速度是一塊磁盤的N倍。讀取時也同樣,所以RAID0具備極快的數據讀寫速度,可是RAID0不作數據備份,N塊磁盤中只要有一塊損壞,數據完整性就被破壞,全部磁盤的數據都會損壞。

RAID 1

數據在寫入磁盤時,將一份數據同時寫入兩塊磁盤,這樣任何一塊磁盤損壞都不會致使數據丟失,插入一塊新磁盤就能夠經過複製數據的方式自動修復,具備極高的可靠性。

RAID 10

結合RAID0和RAID1兩種方案,將全部磁盤平均分紅兩份,數據同時在兩份磁盤寫入,至關於RAID1,可是在每一份磁盤裏面的N/2塊磁盤上,利用RAID0技術併發讀寫,既提升可靠性又改善性能,不過RAID10的磁盤利用率較低,有一半的磁盤用來寫備份數據。

RAID 3

通常狀況下,一臺服務器上不會出現同時損壞兩塊磁盤的狀況,在只損壞一塊磁盤的狀況下,若是能利用其餘磁盤的數據恢復損壞磁盤的數據,這樣在保證可靠性和性能的同時,磁盤利用率也獲得大幅提高。

在數據寫入磁盤的時候,將數據分紅N-1份,併發寫入N-1塊磁盤,並在第N塊磁盤記錄校驗數據,任何一塊磁盤損壞(包括校驗數據磁盤),均可以利用其餘N-1塊磁盤的數據修復。

可是在數據修改較多的場景中,修改任何磁盤數據都會致使第N塊磁盤重寫校驗數據,頻繁寫入的後果是第N塊磁盤比其餘磁盤容易損壞,須要頻繁更換,因此RAID3不多在實踐中使用。

RAID 5

RAID5和RAID3很類似,可是校驗數據不是寫入第N塊磁盤,而是螺旋式地寫入全部磁盤中。這樣校驗數據的修改也被平均到全部磁盤上,避免RAID3頻繁寫壞一塊磁盤的狀況。

RAID 6

若是數據須要很高的可靠性,在出現同時損壞兩塊磁盤的狀況下,仍然須要修復數據,這時候可使用RAID6。RAID6和RAID5相似,可是數據只寫入N-2塊磁盤,並螺旋式地在兩塊磁盤中寫入校驗信息(使用不一樣算法生成)。

各類RAID技術的比較以下表所示。

RAID類型 訪問速度 數據可靠性 磁盤利用率
RAID0 很快 很低 100%
RAID1 很慢 很高 50%
RAID10 中等 很高 50%
RAID5 較快 較高 (N - 1)/ N
RAID6 較快 較高 (N - 2)/ N

RAID技術能夠經過硬件實現,好比專用的RAID卡或者主板直接支持,也能夠經過軟件實現。RAID技術在傳統關係數據庫及文件系統中應用比較普遍,可是在大型網站比較喜歡使用的NoSQL,以及分佈式文件系統中,RAID技術卻遭到冷落。

相關文章
相關標籤/搜索