《大型網站技術架構:核心原理與案例分析》

《大型網站技術架構:核心原理與案例分析》

目錄

大型網站架構演化

打造一個高可用、高效能、易擴充套件、可伸縮且安全的網站。

大型網站軟體系統的特點

  • 高併發、大流量:需要面對高併發使用者,大流量訪問。

  • 高可用:系統7×24小時不間斷服務。

  • 海量資料:需要儲存、管理海量資料,需要使用大量伺服器。

  • 使用者分佈廣泛,網路情況複雜:許多大型網際網路都是為全球使用者提供服務的,使用者分佈範圍廣,各地網路情況千差萬別。

  • 安全環境惡劣:由於網際網路的開放性,使得網際網路站更容易受到攻擊,大型網站幾乎每天都會被黑客攻擊。

  • 需求快速變更,釋出頻繁:和傳統軟體的版本釋出頻率不同,網際網路產品為快速適應市場,滿足使用者需求,其產品釋出頻率是極高的。

  • 漸進式發展:與傳統軟體產業或企業應用系統一開始就規劃好全部的功能和非功能需求不同,幾乎所有的大型網際網路站都是從一個小網站開始,漸進地發展起來的。

大網站架構演化發展歷程

1. 初始階段的網站架構

初始階段的網站架構

應用程式、資料庫、檔案等所有的資源都在一臺伺服器上。

2. 應用服務和資料服務分離

應用服務和資料服務分離

  • 應用伺服器:需要處理大量的業務邏輯,因此需要更快更強大的CPU

  • 資料庫伺服器:需要快速磁碟檢索和資料快取,因此需要更快的硬碟和更大的記憶體

  • 檔案伺服器:需要儲存大量使用者上傳的檔案,因此需要更大的硬碟

3. 使用快取改善網站效能

網站使用快取

  • 快取在應用伺服器上的本地快取:訪問速度更快,但是受應用伺服器記憶體限制,其快取資料量有限,而且會出現和應用程式爭記憶體的情況。

  • 快取在專門的分散式快取伺服器上的遠端快取:遠端分散式快取可以使用叢集的方式,部署大記憶體的伺服器作為專門的快取伺服器,可以在理論上做到不受記憶體容量限制的快取服務。

4. 使用應用伺服器叢集改善網站的併發處理能力

應用伺服器叢集部署

負載均衡排程伺服器:將來自使用者瀏覽器的訪問請求分發到應用伺服器叢集中的任何一臺伺服器上。

5. 資料庫讀寫分離

資料庫讀寫分離

主從熱備功能:通過配置兩臺資料庫主從關係,可以將一臺資料庫伺服器的資料更新同步到另一臺伺服器上。

應用伺服器在寫資料庫的時候,訪問主資料庫,主資料庫通過主從複製機制將資料更新同步到從資料庫,這樣當應用伺服器讀資料的時候,就可以通過從資料庫獲得資料。為了便於應用程式訪問讀寫分離後的資料庫,通常在應用伺服器端使用專門的資料訪問模組,使資料庫讀寫分離對應用透明。

6. 使用反向代理和CDN加速網站響應

網站使用反向代理和CDN加速訪問

CDN和反向代理:基本原理都是快取,區別在於CDN部署在網路提供商的機房,使使用者在請求網站服務時,可以從距離自己最近的網路提供商機房獲取資料;反向代理則部署在網站的中心機房,當使用者請求到達中心機房後,首先訪問的伺服器是反向代理伺服器,如果反向代理伺服器中快取著使用者請求的資源,就將其直接返回給使用者。

7. 使用分散式檔案系統和分散式資料庫系統

使用分散式檔案系統和分散式資料庫系統

分散式資料庫:是網站資料庫拆分的最後手段,只有在表單資料規模非常龐大的時候才使用。不到不得已時,網站更常用的資料庫拆分手段是業務分庫,將不同業務的資料庫部署在不同的物理伺服器上。

8. 使用NoSQL和搜尋引擎

使用NoSQL和搜尋引擎

NoSQL和搜尋引擎:源自網際網路的技術手段,對可伸縮的分散式特性具有更好的支援。應用伺服器則通過一個統一資料訪問模組訪問各種資料,減輕應用程式管理諸多資料來源的麻煩。

9. 業務拆分

業務拆分

業務拆分:根據產品線劃分,將一個網站拆分成許多不同的應用,每個應用獨立部署維護。應用之間可以通過一個超連結建立關係(在首頁上的導航連結每個都指向不同的應用地址),也可以通過訊息佇列進行資料分發,當然最多的還是通過訪問同一個資料儲存系統來構成一個關聯的完整系統。

10. 分散式服務

分散式服務

分散式服務:可以將應用系統中共用的業務提取出來,獨立部署。這些可複用的業務連線資料庫,提供共用業務服務,而應用系統只需要管理使用者介面,通過分散式服務呼叫共用業務服務完成具體業務操作。

大型網站架構演化的價值觀

  1. 大型網站架構技術的核心價值是隨網站所需靈活應對

  2. 驅動大型網站技術發展的主要力量是網站的業務發展

網站架構設計誤區

  1. 一味追隨大公司的解決方案

  2. 為了技術而技術

  3. 企圖用技術解決所有問題

大型網站架構模式

模式的關鍵在於模式的可重複性,問題與場景的可重複性帶來解決方案的可重複使用。

網站架構模式

為了解決大型網站面臨的高併發訪問、海量資料處理、高可靠執行等一系列問題與挑戰,大型網際網路公司在實踐中提出了許多解決方案,以實現高效能、高可用、易伸縮、可擴充套件、安全等各種技術架構目標。這些解決方案又被更多網站重複使用,從而逐漸形成大型網站架構模式。

1. 分層

層級功能
應用層負責具體業務和試圖展示
服務層為應用層圖個服務支援
資料層提供資料儲存訪問服務

在實踐中,大的分層結構內部還可以繼續分層,如:

  • 應用層

    • 檢視層(美工負責)

    • 業務邏輯層(工程師負責)

  • 服務層

    • 資料介面層(適配各種輸入和輸出的資料格式)

    • 邏輯處理層

2. 分割

如果說分層是將軟體在橫向方面進行切分,那麼分割就是在縱向方面對軟體進行切分。

3. 分散式

對於大型網站,分層和分割的一個主要目的是為了切分後的模組便於分散式部署,即將不同模組部署在不同的伺服器上,通過遠端呼叫協同工作。

分散式解決網站高併發帶來問題:

  • 分散式意味著服務呼叫必須通過網路,這可能對效能造成比較嚴重的影響。

  • 伺服器越多,伺服器宕機的概率也就越大,一臺伺服器宕機造成的伺服器不可用可能會導致很多應用不可訪問,使網站可用性降低。

  • 資料在分散式環境中保持資料一致性也非常困難。

  • 分散式導致網站依賴錯綜複雜,開發管理維護困難。

在網站應用中,常用的分散式方案有以下幾種:

  • 分散式應用和服務:將分層和分割後的應用和服務模組分散式部署。

    • 改善網站效能和併發性

    • 加快開發和釋出速度

    • 減少資料庫連線資源消耗

    • 使不同應用複用共同的服務

    • 便於業務功能的擴充套件

  • 分散式靜態資源:網站的靜態資源獨立分散式部署,並採用獨立的域名,“動靜分離”。

    • 減輕應用伺服器的負載壓力

    • 加快瀏覽器併發載入的速度

    • 有利於網站分工合作

  • 分散式資料和儲存:傳統關聯式資料庫和各種NoSQL幾乎都是分散式的。

  • 分散式計算:目前網站普遍使用Hadoop及其MapReduce分散式計算框架進行此類批處理計算,其特點是移動計算而不是移動資料,將計算程式分發到資料所在位置以加速計算和分散式計算。

  • 分散式配置:支援網站線上伺服器配置實時更新。

  • 分散式鎖:分散式環境下實現併發和協同。

  • 分散式檔案:支援雲端儲存。

4. 叢集

使用分散式已經將分層和分割後的模組獨立部署,對於使用者訪問集中的模組(如網站首頁),還需要將獨立部署的伺服器叢集化,即多臺伺服器部署相同應用構成一個叢集,通過負載均衡裝置共同對外提供服務。

5. 快取

快取就是將資料存放在距離計算最近的位置以加快處理速度。快取是改善軟體效能的第一手段。

  • CDN:即內容分發網路,部署在距離使用者最近的網路服務商,使用者的網路請求總是先到達網路服務商那裡,在這裡快取網站的一些靜態資源(較少變化的資料),就可以以最快速度返回給使用者。

  • 反向代理:屬於網站前端架構的一部分,部署在網站的前端,當使用者請求到達網站的資料中心時,最先訪問到的就是反向代理伺服器,這裡環迅網站的靜態資源,無需將請求繼續轉發給應用伺服器就能返回給使用者。

  • 本地快取:在應用伺服器本地快取著熱點資料,應用程式可以在本機記憶體中直接訪問資料,而無需訪問資料庫。

  • 分散式快取:將資料快取在一個專門的分散式快取叢集中,應用程式通過網路通訊訪問快取資料。

使用快取兩個前提條件:

  • 資料訪問熱點不均衡,某些資料會被更頻繁的訪問,這些資料應該放在快取中。

  • 資料在某個時間段內有效,不會很快過期,否則快取的資料會因已經失效而產生髒讀,影響結果的正確性。

6. 非同步

系統解耦的手段除了分層、分割、分佈等,還有非同步。業務之間的訊息傳遞不是同步呼叫,二十將一個業務操作分成多個階段,每個階段之間通過共享資料的方式非同步執行進行協作。

  • 在單一伺服器內通過多執行緒共享記憶體佇列的方式實現非同步。

  • 在分散式系統中多個伺服器叢集通過分散式訊息佇列實現非同步,分散式訊息佇列可看做記憶體佇列的分散式部署。

非同步架構是典型的生產者消費者模式,兩者不存在直接呼叫,只要保持資料結構不變,彼此功能實現可以隨意變化而不互相影響,這對網站擴充套件新功能非常便利。除此之外,使用非同步訊息佇列還有如下特性:

  • 提高系統可用性:消費者伺服器發生故障,資料會在訊息佇列伺服器中儲存堆積,生產者伺服器可以繼續處理業務請求,系統整體表現無故障。消費者伺服器回覆正常後,繼續處理訊息佇列中的資料。

  • 加快網站響應速度:處在業務處理前端的生產者伺服器在處理完業務請求後,將資料寫入訊息佇列,不需要等待消費者伺服器處理就可以返回,響應延遲減少。

  • 消除併發訪問高峰:使用訊息佇列將突然增加的訪問請求資料放入訊息佇列中,等待消費者伺服器依次處理,就不會對整個網站造成太大壓力。

7. 冗餘

訪問和負載很小的服務也必須部署至少兩臺伺服器構成一個叢集,母的是通過冗餘實現伺服器高可用。資料庫除了定期備份,存檔儲存,實現冷備份外,為了保證線上業務高可用,還需要對資料庫進行主從分離,實時同步實現熱備份

8. 自動化

  • 釋出過程自動化
  • 自動化程式碼管理
  • 自動化測試
  • 自動化安全檢測
  • 自動化部署
  • 自動化監測
  • 自動化報警
  • 自動化失效轉移
  • 自動化失效恢復
  • 自動化降級
  • 自動化分配資源

9. 安全

  • 通過密碼手機校驗碼進行身份認證
  • 登入、交易等操作需要對網路通訊進行加密
  • 防止機器人程式攻擊網站,使用驗證碼識別
  • 對於常見的用於攻擊網站的XSS攻擊、SQL隱碼攻擊等相應處理
  • 對於垃圾資訊、敏感資訊進行過濾
  • 對交易轉賬等重要操作根據交易模式和交易資訊進行風險控制

架構模式在新浪微博的應用

新浪微博的系統架構
相關連結

  • 基礎服務層:提供資料庫、快取、儲存、搜尋等資料服務,以及其他一些基礎技術服務,這些服務支撐了新浪微博的海量資料和高併發訪問,是整個系統的技術基礎。

  • 中間層(平臺服務和應用服務層):新浪微博的核心服務是微博、關係和使用者,這些服務被分割成為獨立的服務模組,通過依賴呼叫和共享基礎資料構成呢個的新浪微博業務基礎。

  • API和業務層:各種客戶端(包括Web網站)和第三方應用,通過呼叫API整合到新浪微博的系統中,共同組成一個生態系統。

這些被分層和分割後的業務模組與基礎技術模組分散式部署,每個模組都部署在一組獨立的伺服器叢集上,通過遠端呼叫的方式進行依賴訪問。

小結

好的設計絕對不是模仿,不是生搬硬套某個模式,而是對問題深刻理解之上的創造與創新。

大型網站核心架構要素

架構:最高層次的規劃,難以改變的命運

軟體架構:有關軟體整體結構與元件的抽象描述,用於指導大型軟體系統各個方面的設計。

軟體架構:效能、可用性、伸縮性、擴充套件性和安全性。

效能

  • 瀏覽器端:通過瀏覽器快取、使用頁面壓縮、合理佈局頁面、減少Cookie傳輸等手段改善效能。

  • CDN:將網站靜態內容分發至離使用者最近的網路服務商機房,使使用者通過最短訪問路徑獲取資料。

  • 反向代理伺服器:快取熱點檔案,加快請求響應速度,減輕應用伺服器負載壓力。

  • 應用伺服器端:本地快取和分散式快取,通過快取在記憶體中的熱點資料處理使用者請求,加快請求處理過程,減輕資料庫負載壓力

  • 非同步操作:將使用者請求傳送至訊息佇列等待後續任務處理,而當前請求直接返回響應給客戶。

  • 叢集:將多臺伺服器組成一個叢集共同對外服務,提高整體處理能力,改善效能。

  • 程式碼層面:通過使用多執行緒、改善記憶體管理等手段優化效能。

  • 資料庫伺服器端:索引、快取、SQL優化等效能優化手段已經比較成熟,NoSQL資料庫通過優化資料模型、儲存結構、伸縮性等手段在效能方面的優勢日趨明顯。

可用性

網站高可用框架設計的前提是必然會出現伺服器宕機,而高可用設計的目標就是當伺服器宕機的時候,服務或者應用依然可用。

網站高可用的主要手段是冗餘,應用部署在多臺伺服器上同時提供訪問,資料儲存在多臺伺服器上互相備份,任何一臺伺服器宕機都不會影響應用的整體可用,也不會導致資料丟失。

  • 對應用伺服器:多臺伺服器通過負載均衡裝置組成一個叢集共同對外提供服務,任何一臺伺服器宕機,只需要把請求切換到其他伺服器就可以實現應用的高可用,但是一個前提條件是應用伺服器上不能儲存請求的會話資訊。

  • 對儲存伺服器:需要對資料進行實時備份,當伺服器宕機時需要將資料訪問轉移到可用的伺服器上,並進行資料恢復以保證繼續有伺服器宕機的時候資料依然可用。

  • 對軟體質量保證:通過預釋出驗證、自動化測試、自動化測試、自動化釋出、灰度釋出等手段,減少將故障引入線上環境的可能,避免故障範圍擴大。

伸縮性

伸縮性是指通過不斷向叢集中加入伺服器的手段來緩解不斷上升的使用者併發訪問壓力和不斷增長的資料儲存需求。 
衡量架構伸縮性的主要標準就是是否可用多臺伺服器構建叢集,是否容易向叢集中新增新的伺服器。加入新的伺服器後是否可以提供和原來伺服器無差別的服務。叢集中可容納的總的伺服器數量是否有限制。

  • 對於應用伺服器叢集:只要伺服器上不儲存資料,所有的伺服器都是對等的,通過使用合適的負載均衡裝置就可以向叢集中不斷加入伺服器。

  • 對於快取伺服器叢集:加入新的伺服器可能會導致快取路由失效,進而導致叢集中大部分快取資料都無法訪問。雖然快取的資料可以通過資料庫重新載入,但是如果應用已經嚴重依賴快取,可能會導致整個網站崩潰。需要改進快取路由演算法保證快取資料的可訪問性。

  • 對於關聯式資料庫:雖然支援資料複製,主從熱備等機制,但是很難做到大規模叢集的可伸縮性,因此關聯式資料庫的叢集伸縮性方案必須在資料庫之外實現,通過路由分割槽等手段將部署有多個資料庫的伺服器組成一個叢集。

  • 對於NoSQL資料庫:為海量資料而生,因此其對伸縮性的支援通常非常好,可以做到在較少運維參與的情況下實現叢集規模的線性伸縮。

擴充套件性

網站的擴充套件性架構直接關注網站的功能需求。

衡量網站架構擴充套件性好壞的主要標準就是在網站增加新的業務產品時,是否可以實現對現有產品透明無影響,不需要任何改動或者很少改動既有業務功能就可以上線新產品。

  • 事件驅動架構:通常利用訊息佇列實現,將使用者請求和其他業務時間構造成訊息釋出到訊息佇列,訊息的處理者作為消費者從訊息佇列中獲取訊息進行處理。通過這種方式將訊息產生和訊息處理分離開來,可以透明地增加新的訊息生產者任務或者新的訊息消費者任務。

  • 分散式服務:將業務和可複用服務分離開,通過分散式服務框架呼叫。新增產品可以通過呼叫可複用的服務實現自身的業務邏輯,而對現有產品沒有任何影響。可複用服務升級變更的時候,也可以通過提供多版本服務對應用實現透明升級,不需要強制應用同步變更。

  • 開放平臺介面:吸引第三方開發者,呼叫網站服務,使用網站資料開發周邊產品,擴充套件網站業務。

安全性

網站的安全架構就是保護網站不受惡意訪問和攻擊,保護網站的重要資料不被竊取。

小結

效能、可用性、伸縮性、擴充套件性和安全性是網站架構最核心的幾個要素。

瞬時響應:網站的高效能架構

網站效能是客觀指標,可以具體體現到響應時間、吞吐量等技術指標,同時也是主觀的感受,而感受則是一種與參與者相關的微妙的東西,使用者的感受和工程師的感受不同,不同的使用者感受也不同。

網站效能測試

不同視角下的網站效能

1. 使用者視角的網站效能

從使用者角度,網站效能就是使用者在瀏覽器上直觀感受到的網站響應素的快還是慢。

使用者感受到的時間,包括使用者計算機和網站服務通訊的時間、網站伺服器處理的時間、使用者計算機瀏覽器構造請求解析響應資料的時間。

使用者視角的網站效能

在實踐中使用一些前端優化手段:

  • 優化HTML式樣
  • 利用瀏覽器端的併發和非同步特性
  • 調整瀏覽器快取策略
  • 使用CDN服務
  • 反向代理

2. 開發人員視角的網站效能

開發人員關注的主要是應用程式本身及其相關子系統的效能,包括響應延遲、系統吞吐量、併發處理能力、系統穩定性等技術指標。

主要優化手段:

  • 快取加速資料讀取
  • 使用叢集提高吞吐能力
  • 使用非同步訊息加快請求響應及實現削峰
  • 使用程式碼優化手段改善程式效能

    1. 運維人員視角的網站效能

主要優化手段:

  • 建設優化骨幹網
  • 使用高價效比定製伺服器
  • 利用虛擬化技術優化資源利用

效能測試指標

1. 響應時間

響應時間是系統最重要的效能指標,直觀地反映了系統的“快慢”。

常用系統操作響應時間表

實踐中通常採用的辦法是重複請求,得到單次請求的響應時間。

2. 併發數

指系統能夠同時處理請求的數目,這個數字也反映了系統的負載特性。

網站系統使用者數 >> 網站線上使用者數 >> 網站併發使用者數

測試程式通過多執行緒模擬併發使用者的辦法來測試系統的併發處理能力,為了真實模擬使用者的行為,測試程式並不是啟動多執行緒然後不停地傳送請求,而是在兩次請求之間加入一個隨機等待時間,這個時間被稱作思考時間

3. 吞吐量

指單位時間內系統處理的請求數量,體現系統的整體處理能力。 
TPS(每秒事物數)是吞吐量的一個常用量化指標,還有HPS(每秒HTTP請求數、QPS(每秒查詢數)等。

在系統併發數由小逐漸增大的過程中(伴隨著伺服器系統資源消耗逐漸增大),系統吞吐量先是逐漸增加,達到一個極限後,隨著併發數的增加範兒下降,達到系統崩潰點後,系統資源耗盡,吞吐量為零。

這個過程中,響應時間現實小幅度上升,達到吞吐量極限後,快速上升,到達系統崩潰點後,系統失去響應。

4. 效能計數器

效能計數器是描述伺服器或作業系統效能的一些資料指標,包括System Load、物件與執行緒數、記憶體使用、CPU使用、磁碟與網路I/O等指標

  • System Load:即系統負載,指當前正在被CPU執行和等待被CPU執行的程序數目總和,是反映系統忙閒程度的重要指標。

效能測試方法

  • 效能測試:以系統設計初期規劃的效能指標為預期目標,對系統不斷施加壓力,驗證系統在資源可接受範圍內,是否能達到效能預期。

  • 負載測試:對系統不斷地增加併發請求以增加系統壓力,直到系統的某項或多項效能指標達到安全臨界值。

  • 壓力測試:查過安全負載的情況下,對系統繼續施加壓力,直到系統崩潰或不能再處理任何請求,以此獲得系統最大壓力承受能力。

  • 穩定性測試:被測試系統在特定硬體、軟體、網路環境條件下,給系統載入一定業務壓力,使系統執行一段較長時間,以此檢測系統是否穩定。在不同生產環境、不同時間點的請求壓力是不均勻的,呈波浪特性,因此為了更好地模擬生產環境,穩定性測試也應不均勻地對系統施加壓力。

效能測試遵循如圖所示拋物線規律:

效能測試曲線

橫座標表示消耗的系統資源,縱座標表示系統處理能力(吞吐量)。

  • a~b段:網站的日常執行區間
  • c點:系統最大負載點
  • d點:系統崩潰點

與效能曲線相對應的是使用者訪問的等待時間(系統響應時間),如:

併發使用者訪問響應時間曲線

在日常執行區間,可以獲得最好的使用者響應時間,隨著併發使用者數的增加,響應延遲越來越大,直到系統崩潰,使用者失去響應。

效能測試報告

測試報告結果反映上述效能測試曲線規律,簡單示例:

效能測試結果報告

效能優化策略

1. 效能分析

  • 檢查請求處理的各個環節的日誌,分析哪個環節響應時間不合理、超過預期。

  • 檢查監控資料,分析影響效能的主要因素是記憶體、磁碟、網路、還是CPU,是程式碼問題還是架構設計不合理,或者系統資源確實不足。

2. 效能優化

  • Web前端效能優化
  • 應用伺服器效能優化
  • 儲存伺服器效能優化

Web前端效能優化

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

瀏覽器訪問優化

1. 減少http請求

主要手段是合併CSS、合併Javascript、合併圖片。 
將瀏覽器一次訪問需要的Javascript、CSS合併成一個檔案,這樣瀏覽器只需要一次請求。

圖片也可以合併,多張圖片合併成一張,如果每張圖片都有不同的超連結,可通過CSS偏移響應滑鼠點選操作構造不同的URL。

2. 使用瀏覽器快取

將更新頻率比較低的、使用頻率比較高的檔案快取在瀏覽器中,可以極好地改善效能。通過設定HTTP頭中的Cache-Control和Expires的屬性,可設定瀏覽器快取,快取時間可以是數天,甚至是幾個月。

某些時候,靜態資原始檔變化需要及時應用到客戶端瀏覽器,可以通過改變檔名實現,即更新Javascript檔案並不是更新Javascript檔案內容,而是生成一個新的Javascript檔案並更新HTML檔案中的引用。

使用瀏覽器快取策略的網站在更新靜態資源時,應採用批量更新的辦法,比如需要更新10個圖示檔案,不宜把10個檔案一次全部更新,二十一個檔案一個檔案逐步更新,並有一定的間隔時間,以免使用者瀏覽器突然大量快取失效,集中更新快取,造成伺服器負載驟增、網路堵塞的情況。

3. 啟用壓縮

在伺服器端對檔案進行壓縮,在瀏覽器端對檔案進行解壓縮,可以有效減少通訊傳輸的資料量。

壓縮對伺服器和瀏覽器產生一定的壓力,在通訊頻寬良好,而伺服器資源不足的情況下要權衡考慮。

4. CSS放在頁面最上面、JavaScript放在頁面最下面

瀏覽器會在下載完全部CSS之後才對整個頁面進行渲染,因此最好的做法是將CSS放在頁面最上面,讓瀏覽器儘快下載CSS。

JavaScript則相反,瀏覽器在載入JavaScript後立即執行,有可能會阻塞整個介面,造成頁面顯示緩慢,因此JavaScript最好放在頁面最下面。

5. 減少Cookie傳輸

太大的Cookie會嚴重影響資料傳輸,儘量減少Cookie中傳輸資料量。

對於某些靜態資源的訪問,如CSS、JavaScript等,傳送Cookie沒有意義,可以考慮靜態資源使用獨立域名訪問,避免請求靜態資源時傳送Cookie,減少Cookie傳輸次數。

CDN加速

CDN(Content Distribute Network,內容分發網路)的本質仍然是一個快取,而且將資料快取存在離使用者最近的地方,使使用者以最快的速度獲取資料,即網路第一跳。

利用CDN的網站架構

CDN能夠快取的一般是靜態資源,但是這些檔案訪問頻度很高。

反向代理

利用反向代理的網站架構

反向代理伺服器具有保護網站安全的作用。

可以通過配置快取功能加速Web請求。

反向代理可以實現負載均衡的功能,通過負載均衡構建的應用叢集可以提高系統總體處理能力,進而改善網站高併發情況下的效能。

應用伺服器效能優化

應用伺服器就是處理網站的伺服器,網站的業務程式碼都部署在這裡,是網站開發最複雜,變化最多的地方,優化手段主要有快取、叢集、非同步等。

分散式快取

網站效能優化第一定律:優先考慮使用快取優化效能。

1. 快取的基本原理

快取指將資料儲存在相對較高訪問速度的儲存媒介中,以供系統處理。一方面快取訪問速度快,可以減少資料訪問的時間,另一方面如果快取的資料是經過計算處理得到的,那麼被快取的資料無需重複計算即可直接使用,因此快取還起到減少計算的作用。

快取的本質:記憶體的Hash表,網站應用中,資料快取以一對Key、Value的形式儲存在記憶體的Hash表中。Hash表資料讀寫的時間複雜度為O(1)。

Hash表儲存例子

快取主要用來存放那些讀寫比很高、變化很少的資料。

使用快取存取資料

2. 合理使用快取

頻繁修改的資料

如果快取中儲存的是頻繁修改的資料,就會出現資料寫入快取後,應用還來不及讀取快取,資料就已失效的情形,徒增系統負擔。一般來說,資料的讀寫比在2:1以上,即寫入一次快取,在資料更新前至少讀取兩次,快取才有意義。

沒有熱點的訪問

快取使用記憶體作為儲存,記憶體資源寶貴而有限,不可能將所有的資料都快取起來,只能將最新訪問的資料快取起來,而將歷史資料清理出快取。

資料不一致與髒讀

一般會對快取的資料設定失效時間,一旦超過失效時間,就要從資料庫中重新載入。因此應用要容忍一定時間的資料不一致。在網際網路應用中,這種延遲通常是可以接受的,但是具體應用仍需慎重對待。還有一種策略是資料更新時立即更新快取,不過這也會帶來更多系統開銷和事務一致性問題。

快取可用性

快取是為提高資料讀取效能的,快取資料丟失或者快取不可用不會影響到應用程式的處理,可以從資料庫直接獲取資料。但是當快取服務崩潰時,資料庫會有可能完全不能承受如此大的壓力而宕機,進而導致整個網站不可用。這種情況被叫做快取雪崩,發生這種故障,甚至不能簡單地重啟快取伺服器和資料庫伺服器來恢復網站訪問。

實踐中,有的網站通過快取熱備等手段提高快取可用性:當某臺快取伺服器宕機時,將快取訪問切換到熱備伺服器上。但是這種設計顯然有違快取初衷,快取不應該被當作可靠的資料來源使用。

通過分散式快取伺服器叢集,將快取資料分佈到叢集多臺伺服器上可在一定程度上改善快取的可用性。當一臺快取伺服器宕機,只有部分快取資料丟失,重新從資料庫載入這部分資料不會對資料庫產生很大影響。

快取預熱

快取中存放的是熱點資料,熱點資料又是快取系統利用LRU(最近最久未用演算法)對不斷訪問的資料篩選淘汰出來的,這個過程需要花費較長的時間。新啟動的快取系統如果沒有任何資料,在重建快取資料的過程中,系統的效能和資料庫負載都不太好,那麼最好在快取系統啟動時就把熱點資料載入好,這個快取預載入手段叫做快取預熱。對於一些後設資料如城市地名列表、類目資訊,可以在啟動時載入資料庫中全部資料到快取進行預熱。

快取穿透

如果因為不恰當的業務、或者惡意攻擊持續高併發地請求某個不存在的資料,由於快取沒有儲存該資料,所有的請求都會落到資料庫上,會對資料庫造成很大壓力,甚至崩潰。一個簡單的對策是將不存在的資料也快取起來(其value值為null)。

3. 分散式快取架構

分散式快取指快取部署在多個伺服器組成的叢集中,以叢集方式提供快取服務,其架構方式有兩種,一種是以JBoss Cache為代表的需要更新同步的分散式快取,一種是以Memcached為代表的不相互通訊的分散式快取。

JBoss Cache:JBoss Cache的分散式快取在叢集中所有伺服器中儲存相同的快取資料,當某臺伺服器有快取資料更新的時候,會通知叢集中其他機器更新快取資料或清除快取資料。

需要更新同步的JBoss-Cache

JBoss Cache通常將應用程式和快取部署在同一臺伺服器上,應用程式可從本地快速獲取快取資料,但是這種方式帶來的問題是快取資料的數量受限於單一伺服器的記憶體空間,而且當叢集規模較大時,快取更新資訊需要同步到叢集所有的機器,其代價驚人。因而這種方案更多見於企業應用系統中,很少在大型網站使用。

Memcached:以後講到。

4. Memcached

簡單的設計、優異的效能、互不通訊的伺服器叢集、海量資料可伸縮的架構。

不互相通訊的Memcached

簡單的通訊洗衣

遠端通訊設計需要考慮兩方面的要素:

  • 通訊協議:即選擇TCP協議還是UDP協議,抑或HTTP協議。
  • 通訊序列化協議:資料傳輸的兩端,必須使用彼此可識別的資料序列化方式才能使通訊得以完成,如XML、JSON等文字序列化協議,或者Google Protobuffer等二進位制序列化序列化協議。

Memcached使用TCP協議(UDP也支援)通訊,其序列化協議則是一套基於文字的自定義協議,以一個命令關鍵字開頭,後面是一組命令運算元。例如讀取一個資料的命令協議是get\。

豐富的客戶端程式

Memcached通訊協議非常簡單,只要支援該協議的客戶端都可以和 Memcached伺服器通訊,因此Memcached發展出非常豐富的客戶端程式,幾乎支援所有主流的網站程式語言。

高效能的網路通訊

Memcached 服務端通訊模組基於Libevent,一個支援事件觸發的網路通訊程式庫。Libevent的設計和實現有許多值得改善的地方,但它在穩定的長連線方面的表現卻正是Memcached需要的。

高效的記憶體管理

Memcached使用了一個非常簡單的辦法——固定空間分配。

Memcached將記憶體空間分為一組slab,每個slab裡又包含一組chunk,同一個slab裡的每個chunk的大小是固定的,擁有相同大小 chunk的slab被組織在一起,叫作slab_class。

Memcached記憶體管理

儲存資料時根據資料的Size大小,尋找一個大於Size的最小chunk將資料寫入。

這種記憶體管理方式避免了記憶體碎片管理的問題,記憶體的分配和釋放都是以chunk為單位的。

Memcached採用LRU演算法釋放最近最久未被訪問的資料佔用的空間,釋放的chunk被標記為未用,等待下一個合大小資料的寫入。

這種方式也會帶來記憶體浪費的問題。

互不通訊的伺服器叢集架構

正是叢集內伺服器互不通訊使得叢集可以做到幾乎無限制的線性伸縮,這也正是目前流行的許多大資料技術的基本架構特點。

非同步操作

使用訊息佇列將呼叫非同步化,可改善網站的擴充套件性。事實上,使用訊息佇列還可改善網站系統的效能。

使用訊息佇列伺服器

  • 在不使用訊息佇列的情況下,使用者的請求資料直接寫入資料庫,在高併發的情況下,會對資料庫造成巨大的壓力,同時也使得響應延遲加劇。

  • 在使用訊息佇列後,使用者請求的資料傳送給訊息佇列後立即返回,再由訊息佇列的消費者程序(通常情況下,該程序通常獨立部署在專門的伺服器叢集上)從訊息佇列中獲取資料,非同步寫入資料庫。由於訊息佇列伺服器處理速度遠快於資料庫(訊息佇列伺服器也比資料庫具有更好的伸縮性),因此使用者的響應延遲可得到有效改善。

訊息佇列具有很好的削峰作用——即通過非同步處理,將短時間高併發產生的事務訊息儲存在訊息佇列中,從而削平高峰期的併發事務。

這裡寫圖片描述

由於資料寫入訊息佇列後立即返回給使用者,資料在後續的業務校驗、 
寫資料庫等操作可能失敗, 因此在使用訊息佇列進行業務非同步處理後,需要適當修改業務流程進行配合,如訂單提交後,訂單資料寫入訊息佇列,不能立即返回使用者訂單提交成功,需要在訊息佇列的訂單消費者程序真正處理完該訂單,甚至商品出庫後,再通過電子郵件或 SMS訊息通知使用者訂單成功,以免交易糾紛。

使用叢集

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

利用負載均衡技術改善效能

程式碼優化

1. 多執行緒

從資源利用的角度看,使用多執行緒的原因主要有兩個:

  • IO阻塞
  • 多CPU

    啟動執行緒數=[任務執行時間/(任務執行時間-IO等待時間)xCPU核心數]

最佳啟動執行緒數和CPU核心數量呈正比,和IO阻塞時間成反比。如果任務都是CPU計算型任務,那麼執行緒數最多不超過CPU核心數。

解決執行緒安全的主要手段:

  • 將物件設計為無狀態物件:無狀態物件是指物件本身不儲存狀態資訊(物件無成員變數,或者成員變數也是無狀態物件),這樣多執行緒併發訪問時候就不會出現狀態不一致。從物件導向設計角度看,無狀態物件時一種不良設計。

  • 使用區域性物件:在方法內部建立物件,這些物件會被每個進入該方法的執行緒建立,除非程式有意識地將這些物件傳遞給其他執行緒,否則不會出現物件被多執行緒併發訪問的清形。

  • 併發訪問資源時使用鎖:多執行緒訪問資源的時候,通過鎖的方式使多執行緒併發操作轉化為順序操作,從而避免資源被併發修改。鎖導致執行緒同步順序執行,可能會對系統效能產生嚴重影響。

2. 資源複用

系統執行時,要儘量減少那些開銷很大的系統資源的建立和銷燬,比如資料庫連線、網路通訊連線、執行緒、複雜物件等。

  • 單例:Java開發常用的物件容器Spring預設構造的物件都是單例(要注意的是 Spring 的單例是 Spring 容器管理的單例,而不是用單例模式構造的單例)。

  • 物件池:通過複用物件例項,減少物件建立和資源消耗。對於資料庫連線物件,每次建立連線,資料庫服務端都需要建立專門的資源以應對,因此頻繁建立關閉資料庫連線,對資料庫伺服器而言是災難性的,同時頻繁建立關閉連線也需要花費較長的時間。因此在實踐中,應用程式的資料庫連線基本都使用連線池(Connection Pool) 的方式。

3. 資料結構

目前比較好的字串 Hash 雜湊演算法有Time33演算法, 即對字串逐字元迭代乘以33,求得 Hash值,演算法原型為:

hash(i) = hash(i-1) * 33   str[i]
  • 1
  • 2

Time33雖然可以較好地解決衝突,但是有可能相似字串的HashCode也比較接近,如字串“AA”的HashCode是2210,字串“AB”的HashCode是2211。 這在某些應用場景是不能接受的,這種情況下,一個可行的方案是對字串取資訊指紋,再對資訊指紋求 HashCode。由於字串微小的變化就可以引起資訊指紋的巨大不同,因此可以獲得較好的隨機雜湊。

通過MD5計算HashCode

4. 垃圾回收

以JVM為例,其記憶體主要可劃分為堆(heap ) 和堆疊(stack)。堆疊用於儲存執行緒上下文資訊,如方法引數、區域性變數等。堆則是儲存物件的記憶體空間,物件的建立和釋放、垃圾回收就在這裡進行。通過對物件生命週期的觀察,發現大部分物件的生命週期都極其短暫,這部分物件產生的垃圾應該被更快地收集,以釋放記憶體,這就是 JVM 分代垃圾回收。

JVM分帶垃圾回收機制

儲存效能優化

機械硬碟 VS 固態硬碟

  • 機械硬碟在資料連續訪問(要訪問的資料儲存在連續的磁碟空間上)和隨機訪問(要訪問的資料儲存在不連續的磁碟空間)時,由於移動磁頭臂的次數相差巨大,效能表現差別也非常大。
  • 可以像記憶體一樣快速隨機訪問。而且 SSD 具有小的功耗和更少的磁碟震動與噪聲。

在網站應用中,大部分應用訪問資料都是隨機的,這種情況下 SSD 具有更好的效能表現。

B 樹 VS LSM樹

  • 為了改善資料訪問特性,檔案系統或資料庫系統通常會對資料排序後儲存,加快資料檢索速度,這就需要保證資料在不斷更新、插入、刪除後依然有序,傳統關聯式資料庫的做法是使用B 樹。

B 樹原理示意圖

B 樹是一種專門針對磁碟儲存而優化的 N 叉排序樹,以樹節點為單位儲存在磁碟中,從根開始查詢所需資料所在的節點編號和磁碟位置,將其載入到記憶體中然後繼續查詢,直到找到所需的資料。

目前資料庫多采用兩級索引的 B 樹,樹的層次最多三層。因此可能需要 5 次磁碟訪問才能更新一條記錄(三次磁碟訪問獲得資料索引及行ID然後再進行一次資料檔案讀操作及一次資料檔案寫操作)。

  • 目前許多 NoSQL 產品釆用 LSM 樹作為主要資料結構。

LSM樹原理示意圖

LSM 樹可以看作是一個 N 階合併樹。資料寫操作(包括插入、修改、刪除)都在記憶體中進行,並且都會建立一個新記錄(修改會記錄新的資料值,而刪除會記錄一個刪除標誌 ),這些資料在記憶體中仍然還是一棵排序樹,當資料量超過設定的記憶體閾值後,會將這棵排序樹和磁碟上最新的排序樹合併。當這棵排序樹的資料量也超過設定閾值後,和磁碟上下一級的排序樹合併。合併過程中,會用最新更新的資料覆蓋舊的資料(或者記錄為不同版本)。

在需要進行讀操作時,總是從記憶體中的排序樹幵始搜尋,如果沒有找到,就從磁碟上的排序樹順序查詢。

在 LSM 樹上進行一次資料更新不需要磁碟訪問,在記憶體即可完成,速度遠快於 B 樹。當資料訪問以寫操作為主,而讀操作則集中在最近寫入的資料上時,使用 LSM 樹可以極大程度地減少磁碟的訪問次數,加快訪問速度。

作為儲存結構,B 樹不是關聯式資料庫所獨有的,NoSQL 資料庫也可以使用 B 樹。同理,關聯式資料庫也可以使用LSM。

RAID VS HDFS

RAID (廉價磁碟冗餘陣列)技術主要是為了改善磁碟的訪問延遲,增強磁碟的可用性和容錯能力。目前伺服器鈒別的計算機都支援插入多塊磁碟(8塊或者更多 ),通過使用RAID技術,實現資料在多塊磁碟上的併發讀寫和資料備份。

常見的RAID技術:

常用RAID技術原理圖

  • RAID0:具有極快的資料讀寫速度,但是RAID0不做資料備份,因為磁碟中只要有一塊損壞,資料完整性就被破壞,所有磁碟的資料都會損壞。

  • RAID1:任何一塊磁碟的損壞都不會導致資料丟失,插入一塊新磁碟就可以通過複製資料的方式自動修復,具有極高的可靠性。

  • RAID10:結合RAID0和RAID1兩種方案,提高可靠性改善效能,RAID10磁碟利用率較低,有一半磁碟用來寫備份資料。

  • RAID3:RAID3很少在實踐中使用。

  • RADI5:RAID5被更多的使用,避免RAID3頻繁寫壞一塊磁碟的情況。

  • RAID6:資料可靠,在出現同時損壞兩塊磁碟的情況下,仍然可以修復資料。

幾種RAID技術比較

RAID 技術可以通過硬體實現,比如專用的RAID卡或者主機板直接支援,也可以通過軟體實現。RAID技術在傳統關聯式資料庫及檔案系統中應用比較廣泛,但是在大型網站比較喜歡使用的NoSQL以及分散式檔案系統中,RAID技術卻遭到冷落。

HDFS以塊(Block) 為單位管理檔案內容,一個檔案被分割成若干個Block當應用程式寫檔案時,每寫完一個Block,HDFS就將其自動複製到另外兩臺機器上,保證每個Block有三個副本,即使有兩臺伺服器宕機,資料依然可以訪問,相當於實現了RAID1的資料複製功能。

當對檔案進行處理計算時,通過MapReduce併發計算任務框架,可以啟動多個計運算元任務(MapReduce Task)同時讀取檔案的多個Block,併發處理,相當於實現了RAID0的併發訪問功能。

HDFS架構原理圖

HDFS配合MapReduce等平行計算框架進行大資料處理時,可以在整個叢集上併發讀寫訪問所有的磁碟,無需RAID支援。

小結

網站效能優化技術是在網站效能遇到問題時的解決方案。而網站的效能問題很多是在使用者高併發訪問時產生的,所以網站效能優化的主要工作是改善高併發使用者訪問情況下的網站響應速度。

網站效能對終端使用者而言是一種主觀感受,效能優化的最終目的就是改善使用者的體驗,使他們感覺網站很快。