大型互聯網系統設計綜述

前言

1994年,中國科學院設立了中國第一個web服務器,推出了中國第一個網站。剛剛過去的2015年雙十一,阿里巴巴當日線上交易額超過700億,支付寶交易峯值爲8.95萬筆/秒。中國的互聯網,正在以難以想象的速度釋放着它的能量。css

大衆對互聯網爆炸式的需求,不斷推進着互聯網技術向着更高的層次發展,從最初的靜態新聞展現,到大型的電子商務平臺,網站技術突飛猛進。也許在四五年前,咱們談到網站製做,想到的仍是Html、IIS、論壇系統,可是如今推出一個網站,已經不是簡簡單單開發一套供人瀏覽的Html那麼容易,而是要克服高併發、高可用、大容量、體驗友好、可擴展等諸多設計和技術上的難題。html

本文從技術角度簡要分析設計大型互聯網系統的一些考慮因素,沒有高深之語,只是工做讀書之餘的總結。前端

1、互聯網技術的學習歷程

事物的發展老是按部就班,不可能一蹴而就。java

2003年的淘寶網最初是基於經典的開源黃金搭檔LAMP(Linux+Apache+Mysql+PHP)創建的。當時的淘寶,比如學武之人剛剛練就一套太祖長拳,只是可以作到行走江湖不吃虧。後來隨着業務的不斷擴大,系統通過不斷從新設計和優化,可以支撐的訪問量也從百萬級別逐漸上升的千萬級別。此時的淘寶網,就已經脫胎換骨,不但吸收了衆家之長融會貫通,並且可以自創武功,足以笑傲江湖了。linux

一、仍是從最簡單的場景提及。搭建一個網站其實很簡單,寫幾個Html文件,運行一個web服務器軟件,就能夠經過瀏覽器訪問之,這樣網站就算建成了,可以爲用戶提供瀏覽html網頁的服務。git

二、靜態的Html網頁其實沒什麼看頭,沒有新鮮的資訊吸引用戶的網站是不會有什麼訪問量的,因而動態網頁技術應運而生。管理員能夠隨時發佈和管理資訊,用戶可以看到更多的動態的內容,這種網站能夠稱做是CMS系統,例如帝國CMS、Joomla、PHPCMS等。程序員

大部分同窗通過學校的課程或者自學,都可以掌握製做動態網站的技術,從而掌握從前端Html到後端數據庫的相關技巧。達到這一階段,就具有了行走江湖的資本,能夠憑此手藝掙口飯討生活了。可是此時若沒能訪得明師指點、增加見識,繼而打通任督二脈,則會沉淪於庸常的增刪改查之中,沒法一窺網站技術之堂奧。github

三、所謂的名師指點,就是在大項目中遇到困難,由於困難是最好的老師。web

這裏所說的困難多種多樣:例如指訪問量太大,網站撐不住了;業務需求爆炸,代碼沒法維護;前臺交互繁瑣,頁面難看等等。每個困難要完全解決都不簡單,一代一代的網站構架師,正式從不斷地嘗試解決這些困難的過程當中,成長起來的。算法

此時,最早想到的辦法——借鑑成功的開源框架的經驗。好比經典的SSH框架(Spirng+Struts+Hibernate),採用了通用的MVC分層模式,可以將業務邏輯、前端展現、持久化數據庫隔離,並分別提供比較專業的解決方案;好比BootStrap,解決了前端顯示的風格統一;好比Angularjs,讓程序員從噩夢般的前端開發中脫離出來。在這個階段,咱們參考了各式各樣的框架設計,所謂觀千劍然後識器,心中造成些許的丘壑,但尚不能融會貫通。

四、網站的業務更加複雜、訪問量更大。要求咱們的視線從單純的增刪改查上跳出來,從總體上全面地重構系統。咱們要從前端想到後端,從高可用性考慮到安全性,從用戶角度思考後再轉過身來從開發者角度考慮。這樣咱們被迫站到了新的高度,這是一個前所未見的絕地,沒有現成的方案能夠搬過來使用,在經歷無數次反覆思考和嘗試以後,纔會完成一個軟件工程師到構架師的艱難轉變。 

記得之前據說過一個理論,計算機領域的任何問題均可以經過增長一個虛擬層來解決。大型網站通用的分層策略是將網站分爲應用層、服務層、數據層,下面首先分別討論一下這三個層次所涉及到的技術要點。

2、應用層技術要點

應用層,即利用服務層提供的標準服務,對用戶提供個性化的業務服務。

前端構架是這一層須要考慮的東西,前端框架須要考慮自適應用戶的瀏覽器版本、屏幕尺寸,避免給用戶帶來糟糕的體驗。

爲了提升性能,前端設計須要考慮:

一、合理設置http meta中的緩存指令,利用瀏覽器緩存提升訪問速度

二、爲提升並發訪問鏈接的數目,可將資源至於不一樣的域名之下

三、減小頁面cookies傳輸,提升傳輸效率

四、在服務器壓縮圖片和文件,在瀏覽器端進行解壓,減小傳輸的數據量

五、合併css、JavaScript、合併圖片,減小請求的次數

六、CSS放在頁面最上面,JavaScript放到頁面最下面。瀏覽器會在下載徹底部css以後纔對頁面進行渲染,爲了讓用戶儘快看到頁面,css文件要放在上面;相反,JavaScript加載以後會當即執行,這樣會影響頁面的顯示速度,因此JavaScript要放到頁面下面。

七、自適應的頁面設計,知足不一樣屏幕尺寸的要求

Angularjs是採用JavaScript編寫的客戶端MVC框架,由Google團隊於2012年正式推出,Angularjs致力於幫助開發者編寫現代化的單頁應用,尤爲適用於編寫大量CRUD操做的、具備Ajax風格的富客戶端應用。

Angularjs直接面向html操做,不鼓勵進行DOM級別的操做。最具備吸引力的特性包括雙向數據綁定、模塊依賴注入、自定義指令等等。

Bootstrap是Twitter推出的一個用於前端開發的開源工具包。它由Twitter的設計師Mark Otto和Jacob Thornton合做開發,是一個CSS/HTML框架。附加大量的JavaScript插件,適合對CSS設計不熟悉的開發團隊快速打造自適應的、簡潔的前端頁面。

3、服務層技術要點

服務層,是在業務梳理的基礎上,將功能獨立的業務單獨提取出來,對外提供統一的無狀態的服務,好比用戶管理、產品管理、庫存管理、訂單管理等等。

一、應用層是如何知道有哪些服務可使用呢,這就須要一個高效率的服務註冊、管理、發佈機制,即分佈式服務訪問框架,例如阿里開源的Dubbo(http://dubbo.io/Home-zh.htm)以及谷歌的Grpc。

分佈式服務訪問框架通常能夠分解爲服務提供者(Provider)、服務消費者(Consumer)、註冊中心(Registry)三個部分。

Provider:以接口的方式將服務註冊到Registry,提供的信息包括服務的名稱、版本、依賴、描述、所在機器地址等。

Registry:接收服務註冊請求,對這些服務進行管理和維護,Dubbo採用開源Zookeeper做爲本身的Registry。註冊中心負責將服務註冊信息的更新通知實時的Push給服務消費者(主要是經過Zookeeper的Watcher機制來實現的)。

Consumer:在啓動的時候從服務註冊中心獲取須要的服務註冊信息;將註冊信息緩存到本地;監聽服務註冊信息的變動,如接收到服務註冊中心的服務變動通知,則在本地緩存中更新服務的註冊信息;

)來轉發請求; 對服務提供方的存活進行檢測,若是出現服務不可用的服務提供方,將從本地緩存中剔除;構造請求調用,從本地緩存列表中,採用負載均衡算法,選出合適的服務提供者進行服務調用。


圖1 分佈式服務框架結構

服務路由:若是多個Provider同時提供了相同的服務,就存在一個路由的問題,能夠採用的機制有輪詢、隨機、根據時間的負載均衡機制等。可以實現軟件層次的負載均衡,同時也知足了失效轉移的要求(即一個服務失效,將請求轉移到另一個可用的服務上去)。

底層通訊:基於RPC模式,封裝Netty提供高效的異步IO通訊的能力。

鏈路維護:Provider、Registry、Consumer之間採用心跳檢測機制維護鏈路的可用性,發現鏈路不可用、或者服務不可用時,能夠及時予以告警,實現高可用性。

通訊格式:可選擇使用xml、json等等。

ZooKeeper簡介:http://www.cnblogs.com/mingziday/p/5182550.html

4、數據層技術要點

數據層有時候又稱爲持久層,即將數據持久化到數據庫的過程。隨着數據存儲量的增大,數據查詢會愈來愈慢,單一數據庫服務不能知足大容量的要求,因而對數據層進行改形成爲必然的抉擇。

一、改造數據庫結構,設置合理的索引;將大數據字段進行拆分。

二、數據庫的讀寫分離,由一個讀寫庫拆分爲一個寫庫+若干讀庫的結構,讀寫庫之間經過定時複製機制實現同步。

三、分庫,分爲垂直分庫和水平分庫。垂直分庫是將不一樣的業務數據放到不一樣的數據庫中,水平分庫是指依據某種拆分原則,把一個表分爲相同結構的若干個表,分到不一樣的數據庫中。進行分庫以後,要考慮數據庫之間的聯合查詢該怎麼處理,例如阿里構架師行顛研發的數據庫路由框架DBRoute,統一處理了數據的合併排序分頁,讓程序員像使用一個數據庫同樣使用多個數據庫。

四、支持異構數據庫的統一處理,例如Mysql、Oracle,可以對外展現透明的訪問接口,即對上層屏蔽了不一樣數據庫的差別。

五、數據量持續加大,考慮採用分佈式數據庫中間件,例如阿里的Cobar。不但支持分庫、屏蔽數據庫異構,並且提供動態伸縮的能力,提供SQL的匯聚、分析、和優化能力。

目前比較成熟的分佈式數據庫開源系統主要有Amoeba(http://sourceforge.net/projects/amoeba/)

以及阿里開源的Cobar https://github.com/alibaba/cobar)

六、採用集羣數據庫緩存,使得大部分熱點數據都從緩存獲取,提升數據訪問效率。例如memcached就是一款比較流行的數據庫緩存系統,將在下面一節介紹。

5、緩存技術在互聯網構架中的應用

緩存就是講數據放在距離用戶最近的位置以縮短處理流程、加快傳輸速度。

下面是一個常見的網站訪問流程框架:

 

圖2 緩存在web訪問流程中的位置

一、瀏覽器緩存

http meta中的Cache-Control、Expire等設置,可以控制用戶瀏覽器緩存。

二、CDN

CDN,Content Delivery Network,即內容分發網絡,部署在距離終端用戶最近的網絡服務商的機房裏面(即所謂網絡訪問第一跳),服務器端的大量靜態資源放置於CDN中,是一種比較特殊並且實用的緩存技術。

三、RedWare硬件負載均衡器

基於IP+Port級別的負載均衡器,有效對網絡流量進行分流

鏈路層負載均衡:不一樣於RedWare的Ip級別的負載均衡。顧名思義,鏈路層負載均衡是在TCP協議的鏈路層進行操做。當數據請求到達後,其IP地址並不被修改,修改的是mac地址,將數據包路由給響應的服務器,服務器處理完成後,能夠直接返回數據給客戶,沒必要通過負載均衡器。Linux平臺上最好的鏈路負載均衡器爲LVS(Linux Virtual Server,章文嵩博士發起的最先的開源項目之一)

四、Nginx

反向代理服務器,能夠做爲應用級別的負載均衡器使用,根據Url的不一樣將訪問轉發到不一樣的內部服務器

來自互聯網的訪問請求必須通過反向代理服務器,至關於在web服務器和網絡攻擊之間創建了一個屏障,起到安全防禦的做用;反向代理服務器也能夠配置緩存功能加速web請求;反向代理也能夠實現負載均衡配置,進而改善網站高併發下的性能。

另一款著名的反向代理服務器是Squid,官網http://www.squid-cache.org

五、Varnish

靜態資源(img/css/html)緩存服務器,Nginx根據路由策略,會將靜態資源路由到Varnish,命中後直接返回緩存的資源

六、分佈式緩存服務器

Memcached,最經常使用的分佈式內存對象緩存系統。其緩存服務器和應用服務器分開部署,應用服務器經過Hash路由算法選擇緩存服務器獲取數據,緩存服務器之間不相互通訊,如圖3所示。

和應用服務器集羣不一樣(各個服務器運行相同的應用),分佈式緩存集羣服務器中,不一樣的服務器存儲的是不一樣的數據。

圖3 Memcached集羣和應用服務器的交互

圖4 memcached的訪問模型

memcached:一套分佈式的高速緩存系統,由LiveJournal的Brad Fitzpatrick採用C語言開發,但目前被許多網站使用以提高網站的訪問速度,尤爲對於一些大型的、須要頻繁訪問數據庫的網站訪問速度提高效果十分顯著。 memcached的通訊模塊基於 Libevent ,是一個支持事件觸發的網絡通訊程序庫。採用 key-vaule鍵值對 的方式存數數據,時間複雜度O(1),效率很是高;內存分配借鑑了Linux內存管理的 Slab機制 (尋找大於Size的最小內存塊存儲該數據);採用 LRU算法 淘汰最近最久未被訪問的數據;只支持內存方式存儲。

memcached訪問過程如圖4所示,應用程序輸入須要寫緩存的數據<BEIJING,DATA>,API將BEIJING輸入路由算法模塊,路由算法根據key和memcached集羣服務器列表計算獲得一臺服務器編號NODE1,進而獲得該機器的IP地址和端口10.0.0.0:91000。API調用通訊模塊和NODE1的服務器通訊,將數據<BEIJING,DATA>寫入分佈式緩存中,讀取數據的過程與之相似。
memcached採用固定內存分配,即將空間分配成固定的大小,存儲數據的時候根據Size的大小,尋找一個大於Size的最小chunk將數據寫入,避免頻繁分配性能問題以及內存分片問題,但時也會引入內存浪費的問題。
當考慮加入一個新的緩存服務器的時候,由於路由算法沒有改變,會致使大量的緩存不命中,所以沒法支持動態伸縮,解決方法是採用一致性Hash算法

個人問題是,寫入緩存的數據如何與數據庫的數據保持同步?
這裏介紹一下其它幾種分佈式緩存系統:
Tair: 淘寶開源緩存系統,支持內存/文件級別緩存,採用C++實現。
Redis :C語言實現,支持Set/Map/List等多種數據結構
Ehcache: 健全的,通過驗證的,全特性的,使用普遍的分佈式緩存實現,採用Java實現,支持內存/文件級別的緩存
Oracle coherence:這是一個基於Oracle的收費的緩存系統

緩存預熱:緩存中存放的是熱點數據,這些數據是經過大量用戶的訪問經過LRU算法篩選出來的。若是一開始就可以預料到哪些數據是熱點數據,首先經過必定的手段將他們加載到緩存中,將大大提升緩存的利用率,例如熱點促銷商品的信息,就能夠首先刷到緩存裏面。

6、分佈式技術

在上面提到了分佈式緩存和分佈式服務。所謂的分佈式,就是把不一樣的功能拆分到不一樣的服務器去完成。要注意的是,分佈式並非只有好處沒有壞處。

一、分佈式意味着服務調用必須經過網絡,這可能帶來比較嚴重的性能損耗。

二、分佈式事務給業務的一致性要求帶來很大挑戰。

7、集羣技術

說的簡單點,網站經過集羣的方式將多臺提供相同服務的服務器當作一個總體對外提供服務,經過路由技術決定到底該訪問那一臺服務器。所謂集羣的伸縮性,就是能夠在訪問壓力大的時候,向集羣中添加服務器以緩解壓力;當訪問壓力變小的時候,能夠把部分服務器分流出去,以節省成本。

集羣提升了系統的總體可用性,當發現集羣中的某個機器不可用的時候,能夠將其從服務器剔除併發出告警。

灰度發佈:是集羣應用中的一個技巧,即網站新功能發佈的時候不中斷對外服務。先關閉服務器集羣中部分機器的路由,更新軟件包,重啓服務,啓動路由,當這部分新功能驗證沒有bug後,再用相似的辦法更新其餘服務器的服務。

8、異步

異步的設計思路是:用戶請求發出後,服務端將請求加入消息隊列中,直接返回,由單獨的線程去處理隊列中的請求。由於沒有直接和數據庫進行交互,因此可以很好改善響應速度,在高併發的時刻有很好的削峯做用。

異步消息隊列的思想來源於事件驅動機制,即不依靠簡單直接的函數調用來實現功能,而是藉助事件消息的通訊完成模塊之間的通訊,極大地下降了模塊之間的耦合性

分佈式消息隊列:隊列是一種先進先出的數據結構,分佈式消息隊列能夠看作將這種數據結構部署到獨立的服務器上。應用程序可使用遠程訪問接口分佈式消息隊列,進行消息存取操做,進而實現分佈式的消息存取操做。

分佈式消息隊列利用發佈-訂閱模式工做。消息生產者經過遠程訪問接口將消息推送給消息度激烈服務器,消息隊列服務器將消息寫入本地內存後當即返回成功響應給消息生產者。消息隊列服務器,查找消息訂閱列表,找到須要給消息的消息消費者,並將消息隊列中的消息以FIFO的方式發送給消息消費者。

異步的問題在於,後臺線程在處理隊列中的請求的時候可能會出現校驗、操做數據庫失敗。例如在訂單提交流程中,就不能直接給用戶顯示訂單提交成功,取而代之,能夠顯示「您提交的訂單已被接受,咱們會盡快反饋訂單處理進度,請關注短信或者郵箱」。

目前異步消息處理框架有阿里的消息中間件RocketMQ(http://alibaba.github.io/RocketMQ-docs/document/design/RocketMQ_design.pdf)等等。

RocketMQ介紹:http://www.cnblogs.com/mingziday/p/5182551.html

9、其餘提升性能的方法

一、代碼優化

多線程編程,web服務器也是採用多線程的方式處理用戶的併發請求的:避免全局變量,合理使用,無狀態對象設計;

啓用對象池、鏈接池(阿里Druid數據鏈接池),減小沒必要要的資源損耗。

二、存儲性能優化

採用RAID技術,提升數據讀寫的併發率、安全性

三、操做系統和文件系統

商用Linux操做系統並非專門針對web服務器進行設計,這就須要咱們對Linux的一些設定進行調優,以提升web服務器的數據訪問性能。例如修改linux參數提升Tcpsocket使用的系統內存、修改最大併發連接數等等。

四、頁面靜態化

讓訪問不通過Java系統,只在到達web服務器以後就直接返回了,這樣咱們緩存的是html頁面,不是java數據。這就要求把html頁面中cookies、時間、動態內容單獨抽取出來。這些抽取出來的內容如何再組裝起來呢,有兩種方式,ESI和CSI。

ESI:在Web服務器上作動態內容請求,並將請求插入到html頁面中,當用戶拿到頁面的時候已是一個完整的頁面了。

CSI:在用戶拿到頁面以後,再單獨發送一個js異步請求獲取動態數據,服務器性能會更好,可是用戶體驗上有些延遲。

經過ESI組織成的html頁面也能夠緩存起來,這樣用戶直接衝緩存中直接拿到html,至關於到一個靜態網站簡單取一份數據而已,不涉及具體的邏輯計算,訪問效率是很高的。可是天下沒有完美的解決方案,這種狀況要考慮cache失效問題。

10、其餘技術

一、Session管理

http協議是一種無狀態協議,而業務老是有狀態的,好比購物車、用戶登陸信心等等,在一個集羣的應用服務器中,如何維持session是個必需要考慮的問題。經常使用的方法有session複製、session綁定(會話粘滯)、cookies記錄session等。

最可靠的方式是使用獨立的session服務器,即利用獨立部署的session服務器管理一切session請求。

二、搜索引擎

Apache Lucene,是一款開源的全文檢索系統(http://www.cnblogs.com/xing901022/p/3933675.html)

搜索引擎的原理,將熱點數據經過同步方法從數據庫中讀取到硬盤/緩存裏面。而後對這些數據創建高效的索引,經過全文檢索算法,就可以快速定位出來。

三、服務冪等性

服務重複調用和第一次調用產生的結果相同。

例如一次調用服務超時失敗了,但實際上該服務已經執行完成了。這個時候業務層面會嘗試從新操做,就須要和第一次操做的時候產生同樣的結果。

參考文獻

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

《淘寶技術十年》

《構建高性能WEB站點》

相關文章
相關標籤/搜索