http://www.cnblogs.com/edisonchou/ html
《大型網站技術架構》讀書筆記之六:永無止境之網站的伸縮性架構 node
此篇已收錄至《大型網站技術架構》讀書筆記系列目錄貼,點擊訪問該目錄可獲取更多內容。 算法
首先,所謂網站的伸縮性,指不須要改變網站的軟硬件設計,僅僅經過改變部署的服務器數量就能夠擴大或者縮小網站的服務處理能力。在整個互聯網行業的發展漸進演化中,最重要的技術就是服務器集羣,經過不斷地向集羣中添加服務器來加強整個集羣的處理能力。 數據庫
(1)縱向分離:將業務處理流程上得不一樣部分分離部署,實現系統的伸縮性; 設計模式
(2)橫向分離:將不一樣的業務模塊分離部署,實現系統的伸縮性; 瀏覽器
使用服務器集羣,即將相同服務部署在多臺服務器上構成一個集羣總體對外提供服務。具體來講,集羣伸縮性又分爲應用服務器集羣伸縮性和數據服務器集羣伸縮性。這兩種集羣對於數據狀態管理的不一樣,技術實現也有很大的區別。 緩存
It is said that 當一頭牛拉不動車的時候,不要去尋找一頭更強壯的牛,而是用兩頭牛來拉車。 服務器
(1)應用服務器應該被設計成無狀態的,即應用服務器不存儲請求上下文信息;構建集羣后,每次用戶的請求均可以發到集羣中任意一臺服務器上處理,任何一臺服務器的處理結果都是相同的; 數據結構
(2)HTTP自己是一個無狀態的鏈接協議,爲了支持客戶端與服務器之間的交互,咱們就須要經過不一樣的技術爲交互存儲狀態,而這些不一樣的技術就是Cookie和Session了。 架構
(3)HTTP請求的分發是應用服務器集羣實現伸縮性的核心問題,而負載均衡服務器就是HTTP請求的分發裝置,它是網站必不可少的基礎手段,也被稱爲網站的殺手鐗之一。
負載均衡的實現方式多種多樣,從硬件到軟件,從商業產品到開源產品,應有盡有。可是,實現負載均衡的基礎技術不外乎如下幾種:
(1)HTTP重定向負載均衡 評價:★★
此方案的優勢是簡單易行,缺點是:
①瀏覽器須要兩次請求才能完成一次訪問,性能較差;
②重定向服務器自身的處理能力有可能成爲瓶頸,整個集羣的伸縮性規模有限;
③使用HTTP 302重定向有可能使搜索引擎判斷爲SEO做弊,下降搜索排名;
(2)DNS域名解析負載均衡 評價:★★★
此方案要求在DNS服務器中配置多個A記錄,例如:
www.mysite.com IN A | 114.100.80.1 |
www.mysite.com IN A | 114.100.80.2 |
www.mysite.com IN A | 114.100.80.3 |
此方案的優勢是將負載均衡的工做轉交給了DNS,省掉了網站管理維護負載均衡服務器的麻煩。而缺點是:
①目前的DNS是多級解析,每一級DNS均可能緩存A記錄,當某臺服務器下線後,即便修改了DNS的A記錄,要使其生效仍然須要較長時間。這段期間,會致使用戶訪問已經下線的服務器形成訪問失敗。
②DNS負載均衡的控制權在域名服務商那裏,網站沒法對其作更多改善和管理;
TIPS:事實上,大型網站老是部分使用DNS域名解析,利用域名解析做爲第一級負載均很手段,即域名解析獲得的一組服務器不是實際的Web服務器,而是一樣提供負載均衡的內部服務器,這組內部服務器再進行負載均衡,請求分發到真實的Web服務器上。
(3)反向代理負載均衡 評價:★★★★
Web服務器不須要使用外部IP地址,而反向代理服務器則須要配置雙網卡和內外部兩套IP地址。
此方案的優勢是和反向代理服務器功能集成在一塊兒,部署簡單。缺點是反向代理服務器是全部請求和響應的中轉站,其性能可能會成爲瓶頸。
(4)IP負載均衡 評價:★★★★
此方案優勢在於在內核進程完成數據分發,較反向代理負載均衡(在應用程序中分發數據)有更好的處理性能。缺點是因爲全部請求響應都須要通過負載均衡服務器,集羣的最大響應數據吞吐量不得不受制於負載均衡服務器網卡帶寬。
(5)數據鏈路層負載均衡 評價:★★★★★
此種方式又稱做三角傳輸模式,負載均衡數據分發過程當中不修改IP地址,只修改mac地址,因爲實際處理請求的真實物理IP地址和數據請求目的IP地址一致,因此不須要經過負載均衡服務器進行地址轉換,可將響應數據包直接返回給用戶瀏覽器,避免負載均衡服務器網卡帶寬成爲瓶頸。這種負載均衡方式又稱做直接路由方式(DR)。
使用三角傳輸模式的鏈路層負載均衡是目前大型網站使用最普遍的一種負載均衡手段。在Linux平臺上最好的鏈路層負載均衡開源產品是LVS(Linux Virutal Server)。
前面的方法解決了負載均衡經過何種方式實現,而更爲重要的則是如何從Web服務器列表中計算獲得一臺Web服務器的地址,而這正是負載均衡的核心—算法。這裏簡單介紹一下一般的集中負載均衡計算的算法,若是須要深刻了解請自行百度。
(1)輪詢
全部請求被以此分發到每臺應用服務器上,即每臺服務器須要處理的請求數目都相同,適合於全部服務器硬件都相同的場景。
(2)加權輪詢
根據應用服務器的配置性能的狀況,在輪詢的基礎上,按照配置的權重將請求分發到每一個服務器,高性能的服務器能分配更多的請求。
(3)隨機
此算法比較簡單實用,請求被隨機分配到各個應用服務器,由於好的隨機數自己就很均衡。
(4)最少鏈接
記錄每一個應用服務器正在處理的鏈接數(請求數),將新到的請求分發到最少鏈接的服務器上,應該說,這是最符合負載均衡定義的算法。
(5)源地址散列
根據請求來源的IP地址進行Hash計算獲得應用服務器,這樣來自同一個IP地址的請求總在同一個服務器上處理,該請求的上下文信息能夠存儲在這臺服務器上,在一個會話週期內重複使用,從而實現會話粘滯。
不一樣於應用服務器集羣的伸縮性設計,分佈式緩存集羣的伸縮性不能使用簡單的負載均衡手段來實現。由於:分佈式緩存服務器集羣中緩存的數據各不相同,緩存訪問請求不能夠在緩存服務器集羣中的任意一臺處理,必須先找到緩存有須要的數據的服務器,而後才能訪問。
分佈式緩存集羣伸縮性設計的目標:讓新上線的緩存服務器對整個分佈式緩存集羣影響最小,也就是說新加入緩存服務器後應使整個緩存服務器集羣中已經緩存的數據儘量還被訪問到。
(1)以Memcached爲表明的分佈式緩存集羣的訪問模型
以上圖片展現了一個典型的緩存寫操做,應用程序須要寫緩存數據<'CHENGDU',DATA>,API將KEY('CHENGDU')輸入路由算法模塊,路由算法根據KEY和Memcached服務器集羣列表計算獲得一臺服務器編號(如Node1),進而獲得該機器的IP地址和端口(10.0.0.1:91000)。而後,API調用通訊模塊和編號爲Node1的Memcached服務器進行通訊,將數據<'CHENGDU',DATA>寫入該服務器,至此便完成了一次分佈式緩存的寫操做。
而讀操做和寫操做同樣,使用一樣的路由算法和服務器列表,只要提供相同的KEY(如上面提到的'CHENGDU'),Memcached客戶端老是訪問相通的服務器(如上面計算獲得的Node1)去讀取數據。
(2)以Memcached爲表明的分佈式緩存集羣的伸縮性挑戰
簡單的路由算法(經過使用餘數Hash)沒法知足業務發展時服務器擴容的須要:緩存命中率降低。例如:當3臺服務器擴容至4臺時,採用普通的餘數Hash算法會致使大約75%(3/4)被緩存了的數據沒法正確命中,隨着服務器集羣規模的增大,這個比例會線性地上升。那麼,能夠想象,當100臺服務器的急羣衆加入一臺服務器,不能命中的機率大概是99%(N/N+1),這個結果顯然是沒法接受的。
那麼,可否經過改進路由算法,使得新加入的服務器不影響大部分緩存數據的正確性呢?請看下面的一致性Hash算法。
(3)分佈式緩存的一致性Hash算法
說明:一致性Hash算法是分佈式緩存的核心理論,這裏只是簡單介紹一下,後續有空我會單獨寫一篇文章來詳細介紹一致性Hash算法,以及用C#實現一致性Hash算法。
一致性Hash算法經過一個叫作一致性Hash還的數據結構實現KEY到緩存服務器的Hash映射,以下圖所示:
具體算法過程是:
①先構造一個長度爲0~2^32(2的32次冪)個的整數環(又稱:一致性Hash環),根據節點名稱的Hash值將緩存服務器節點防置在這個Hash環中,如上圖中的node1,node2等;
②根據須要緩存的數據的KEY值計算獲得其Hash值,如上圖中右半部分的「鍵」,計算其Hash值後離node2很近;
③在Hash環上順時針查找距離這個KEY的Hash值最近的緩存服務器節點,完成KEY到服務器的Hash映射查找,如上圖中離右邊這個鍵的Hash值最近的順時針方向的服務器節點是node2,所以這個KEY會到node2中讀取數據;
當緩存服務器集羣須要擴容的時候,只須要將新加入的節點名稱(如node5)的Hash值放入一致性Hash環中,因爲KEY老是順時針查找距離其最近的節點,所以新加入的節點隻影響整個環中的一部分。以下圖中所示,添加node5後,隻影響右邊逆時針方向的三個Key/Value對數據,只佔整個Hash環中的一小部分。
所以,咱們能夠與以前的普通餘數Hash做對比:採用一直性Hash算法時,當3臺服務器擴容到4臺時,能夠繼續命中原有緩存數據的機率爲75%,遠高於普通餘數Hash的25%,並且隨着集羣規模越大,繼續命中原有緩存數據的機率也會隨之增大。當100臺服務器增長1臺時,繼續命中的機率是99%。雖然,仍有小部分數據緩存在服務器中沒法被讀取到,可是這個比例足夠小,經過訪問數據庫也不會對數據庫形成致命的負載壓力。
首先,數據存儲服務器必須保證數據的可靠存儲,任何狀況下都必須保證數據的可用性和正確性。所以,緩存服務器集羣的伸縮性架構方案不能直接適用於數據庫等存儲服務器。
(1)關係數據庫集羣的伸縮性設計
①市場上主要的關係數據庫都支持數據複製功能,使用這個功能能夠對數據庫進行簡單伸縮。下圖顯示了使用數據複製的MySQL集羣伸縮性方案:多臺MySQL的角色有主從之分,寫操做都在主服務器上,由主服務器將數據同步到集羣中其餘從服務器。而讀操做及數據分析等離線操做都會在從服務器上完成。
②前面提到的業務分割模式也能夠用在數據庫,不一樣業務數據表部署在不一樣的數據庫集羣上,這就是所謂的「數據分庫」;可是其有一個制約條件:跨庫的表沒法進行Join操做;
③在實際運維中,對一些單表數據仍然很大的表,例如Facebook的用戶數據庫、淘寶的商品數據庫等,還須要進行分片,將一張表拆分開分別存儲在多個數據庫中,這就是所謂的「數據分片」;
(2)NoSQL數據庫的伸縮性設計
首先,NoSQL主要指非關係的、分佈式的數據庫設計模式。也有許多專家將NoSQL解讀爲Not Only SQL,表示NoSQL是關係數據庫的補充,而不是替代方案。通常而言,NoSQL數據庫產品都放棄了關係數據庫的兩大重要基礎:①以關係代數爲基礎的結構化查詢語言(SQL)②事務的一致性保證(ACID);與之對應的是強化一些大型網站更關注的特性:高可用性和可伸縮性;
開源社區的NoSQL產品不盡其數,其支持的數據結構和伸縮性特性也各不相同。目前看來,應用最普遍的是Apache HBase。HBase的伸縮性主要依賴於其可分裂的HRegion及可伸縮的分佈式文件系統HDFS(若是您不知道HDFS又對HDFS有興趣,能夠閱讀個人另外一篇博文《不怕故障的海量存儲—HDFS基礎入門》)實現。
上圖是HBase的總體架構圖:
①HBase中數據以HRegion爲單位進行管理,也就是說應用程序若是想要訪問一個數據,必須先找到HRegion,而後將數據讀寫操做提交給HRegion,由HRegion完成存儲層面的數據操做。
②每一個HRegion中存儲一段Key區間(例如:[Key1,Key2))的數據,HRegionServer是物理服務器,每一個HRegionServer上能夠啓動多個HRegion實例。當一個HRegion中寫入的數據太多,達到配置的閥值時,HRegion會分裂成兩個HRegion,並將HRegion在整個集羣中進行遷移,以使HRegionServer的負載均衡。
③全部的HRegion的信息都(例如:存儲的Key值區間、所在HRegionServer的IP地址和端口號等)記錄在HMaster服務器上。同時爲了保證高可用,HBase啓動了多個HMaster,並經過ZooKeeper(一個支持分佈式一致性的數據管理服務)選舉出一個主服務器,經過這個主HMaster服務器得到Key值所在的HRegionServer,最後請求該HRegionServer上的HRegion實例,得到須要的數據。其具體的數據尋址訪問流程以下圖所示:
在本章的學習中,咱們瞭解到要實現網站的可伸縮性,關鍵技術就在於如何構建「良好」的服務器集羣。要達到良好的目標,就要求每次擴容和減小服務器時,對整個網站的影響是最小的,甚至無影響的。伸縮性是複雜的,沒有通用的、完美的解決方案和產品。一個具備良好伸縮性的網站,其設計老是走在業務發展的前面,在業務須要處理更多訪問和處理以前,就已經作好了充分的準備,當業務須要時,只須要增長服務器並簡單部署就能夠了,技術團隊即可輕鬆應對了。
在本篇的介紹中,有些核心的內容好比一致性Hash算法只是進行了簡單的介紹,並無深刻的分析,這個源於我目前對其的理解還只是皮毛。等待我深刻學習以後,我會抽空寫一篇單獨介紹一致性Hash算法的博文,並使用C#進行一個粗略的實現,有興趣的朋友敬請期待吧。
另外,前面幾篇博文中有些園友提出介紹一些實踐性質的東西,我在這裏表示抱歉,由於本書只是單純地講解理論,並且也沒有深刻地去講解這些理論,只是單純地擴展知識面,管中窺豹,一覽大型網站的技術體系。而我本人也仍是一個即將求職和畢業的學生,在理論和實踐上都缺少相應的經驗,但我會在精讀完本書後去作一些相應場景的具體實踐,好比使用Memcached或Redis構建分佈式緩存集羣,使用Mono在Linux下搭建ASP.NET MVC應用環境,使用高性能的Nginx或Jexus服務器構建反向代理負載均衡服務器環境,使用發佈訂閱模式實現MS SQL的讀寫分離實踐等等,若是園友有興趣的話,也能夠自行找資料去作相關實踐。若是以爲喜歡個人博文,那我只能說敬請期待了(如今時間寶貴啊,立刻要找工做了,還得複習複習,再過段時間畢業論文的鴨梨又要來了,我勒個去),麼麼嗒。
(1)李智慧,《大型網站技術架構-核心原理與案例分析》,http://item.jd.com/11322972.html
(2)老徐的私房菜,《HTTP無狀態協議和Session原理》,http://laoxu.blog.51cto.com/4120547/1219699
(3)百度百科,《一致性Hash算法》,http://baike.baidu.com/view/1588037.htm
(4)charlee,《Memcached徹底剖析》,http://kb.cnblogs.com/page/42731/
(5)bluishglc,《數據庫Sharding的基本思想和切分策略》,http://blog.csdn.net/bluishglc/article/details/6161475