1. 程式人生 > >【網站架構學習】瞬時響應:應用伺服器效能優化

【網站架構學習】瞬時響應:應用伺服器效能優化

應用伺服器效能優化


一、應用伺服器效能優化

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

1.1、分散式快取

      回顧網站架構演化歷程,當網站遇到效能瓶頸時,第一個想到的解決方案就是使用 快取。在整個網站應用中,快取幾乎無所不在,既存在於瀏覽器,也存在於應用伺服器 和資料庫伺服器;既可以對資料快取,也可以對檔案快取,還可以對頁面片段快取。合 理使用快取,對網站效能優化意義重大。

1.2、快取的基本原理

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

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

      計算KV對中Key的HashCode對應的Hash表索引,可快速訪問Hash表中的資料。 許多語言支援獲得任意物件的HashCode,可以把HashCode理解為物件的唯一標示符,Java 語言中Hashcode方法包含在根物件Object中,其返回值是一個Int。然後通過Hashcode 計算Hash表的索引下標,最簡單的是餘數法,使用Hash表陣列長度對Hashcode求餘, 餘數即為Hash表索引,使用該索引可直接訪問得到Hash表中儲存的KV對。Hash表是 軟體開發中常用到的一種資料結構,其設計思想在很多場景下都可以應用。
在這裡插入圖片描述


      快取主要用來存放那些讀寫比很高、很少變化的資料,如商品的類目資訊,熱門詞 的搜尋列表資訊,熱門商品資訊等。應用程式讀取資料時,先到快取中讀取,如果讀取 不到或資料已失效,再訪問資料庫,並將資料寫入快取
在這裡插入圖片描述
      網站資料訪問通常遵循二八定律,即80%的訪問落在20%的資料上,因此利用Hash 表和記憶體的高速訪問特性,將這20%的資料快取起來,可很好地改善系統性能,提高數 據讀取速度,降低儲存訪問壓力。

1.3、合理使用快取

      使用快取對提高系統性能有很多好處,但是不合理使用快取非但不能提高系統的性 能,還會成為系統的累贅,甚至風險。實踐中,快取濫用的情景屢見不鮮一過分依賴 低可用的快取系統、不恰當地使用快取的資料訪問特性等。

頻繁修改的資料

      如果快取中儲存的是頻繁修改的資料,就會出現資料寫入快取後,應用還來不及讀 取快取,資料就已失效的情形,徒增系統負擔。一般說來,資料的讀寫比在2:1以上,即 寫入一次快取,在資料更新前至少讀取兩次,快取才有意義。實踐中,這個讀寫比通常 非常高,比如新浪微博的熱門微博,快取以後可能會被讀取數百萬次。

沒有熱點的訪問

      快取使用記憶體作為儲存,記憶體資源寶貴而有限,不可能將所有資料都快取起來,只 能將最新訪問的資料快取起來,而將歷史資料清理出快取。如果應用系統訪問資料沒有 熱點,不遵循二八定律,即大部分資料訪問並沒有集中在小部分資料上,那麼快取就沒 有意義,因為大部分資料還沒有被再次訪問就已經被擠出快取了。

資料不一致與髒讀

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

快取可用性

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

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

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

      產品在設計之初就需要一個明確的定位:什麼是產品要實現的功能,什麼 不是產品提供的特性。在產品漫長的生命週期中,會有形形色色的困難和誘惑 來改變產品的發展方向,左右搖擺、什麼都想做的產品,最後有可能成為一個 失去生命力的四不像。

快取預熱

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

快取穿透

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

1.4、分散式快取架構

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

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

      大型網站需要快取的資料量一般都很龐大,可能會需要數TB的記憶體做快取,這時候 就需要另一種分散式快取Memcached採用一種集中式的快取叢集管理, 也被稱作互不通訊的分散式架構方式。快取與應用分離部署,快取系統部署在一組專門 的伺服器上,應用程式通過一致性Hash等路由演算法選擇快取伺服器遠端訪問快取資料, 快取伺服器之間不通訊,快取叢集的規模可以很容易地實現擴容,具有良好的可伸縮性。

1.5、Memcached

      Memcached曾一度是網站分散式快取的代名詞,被大量網站使用。其簡單的設計、 優異的效能、互不通訊的伺服器叢集、海量資料可伸縮的架構令網站架構師們趨之若鶩。在這裡插入圖片描述

簡單的通訊協議

      遠端通訊設計需要考慮兩方面的要素,一是通訊協議,即選擇TCP協議還是UDP協 議,抑或HTTP協議;一是通訊序列化協議,資料傳輸的兩端,必須使用彼此可識別的 資料序列化方式才能使通訊得以完成,如XML、JSON等文字序列化協議,或者Google Protobuffer等二進位制序列化協議。Memcached使用TCP協議(UDP也支援)通訊,其序 列化協議則是一套基於文字的自定義協議,非常簡單,以一個命令關鍵字開頭,後面是 一組命令運算元。例如讀取一個數據的命令協議是get 。Memcached以後,許多 NoSQL產品都借鑑了或直接支援這套協議。

豐富的客戶端程式

      Memcached通訊協議非常簡單,只要支援該協議的客戶端都可以和Memcached服務 器通訊,因此Memcached發展出非常豐富的客戶端程式,幾乎支援所有主流的網站程式設計 語言,Java、C/C++/C#、Perl、Python、PHP、Ruby等,因此在混合使用多種程式語言的 網站,Memcached更是如魚得水。

高效能的網路通訊

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

高效的記憶體管理

      記憶體管理中一個令人頭痛的問題就是記憶體碎片管理。作業系統、虛擬機器垃圾回收在
這方面想了許多辦法:壓縮、複製等。Memcached使用了一個非常簡單的辦法 固定
空間分配。Memcached將記憶體空間分為一組slab,每個slab裡又包含一組chunk,同一個 slab裡的每個chunk的大小是固定的,擁有相同大小chunk的slab被組儲存資料時根據資料的Size大小,尋找一個大於Size的最小 chunk將資料寫入。這種記憶體管理方式避免了記憶體碎片管理的問題,記憶體的分配和釋放都 是以chunk為單位的。和其他快取一樣,Memcached採用LRU演算法釋放最近最久未被訪 問的資料佔用的空間,釋放的chunk被標記為未用,等待下一個合適大小資料的寫入。織在一起,叫作 slab_class,

      當然這種方式也會帶來記憶體浪費的問題。資料只能存入一個比它大的chunk裡,而一 個chunk只能存一個數據,其他空間被浪費了。如果啟動引數配置不合理,浪費會更加驚 人,發現沒有快取多少資料,記憶體空間就用盡了。在這裡插入圖片描述

1.6、非同步操作

      使用訊息佇列將呼叫非同步化,可改善網站的擴充套件性事實上,使用訊息佇列還可改善網站系統的效能
在這裡插入圖片描述

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

      訊息佇列具有很好的削峰作用——即通過非同步處理,將短時間高併發產生的事務消 息儲存在訊息佇列中,從而削平高峰期的併發事務。在電子商務網站促銷活動中,合理 使用訊息佇列,可有效抵禦促銷活動剛開始大量湧入的訂單對系統造成的衝擊在這裡插入圖片描述

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

1.7、使用叢集

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

      三臺Web伺服器共同處理來自使用者瀏覽器的訪問請求,這樣每臺Web伺服器需要處 理的http請求只有總併發請求數的三分之一,根據效能測試曲線,使伺服器的併發請求 數目控制在最佳執行區間,獲得最佳的訪問請求延遲。

1.8、程式碼優化

略:後續再看~
宣告:以上內容來自:《大型網站技術架構:核心原理與案例分析書籍》
下一章:儲存效能優化