這篇文章是參考李智慧的《大型網站技術架構:核心原理與案例分析》和現蘑菇街CTO曽憲杰的《大型網站系統與Java中間件實踐》寫的一篇讀書筆記。
前言
何謂大型網站?大型網站的特點是什么?大型網站架構發生演變的源動力是什么?大型網站的架構演變經歷了哪些階段?在演變的某個具體階段使用到常用技術有哪些,為什么要使用這些技術,同時這些技術又解決了什么問題?筆者在初次接觸大型網站時思考了以上幾個問題,本著緣木求魚的方式,我打算詳細的扒一扒大型網站的演變史。如果對以上的幾個問題都理解透徹了,那么可以說對大型網站也有一個基本的認識和理解了,但是我寫這篇文章卻不局限于此,在文章的后面會從一個中高級程序員的角度去思考,從大型網站的演變史可以得到哪些方法論和技術棧。由于筆者工作時間不長,所以我覺得思考這個問題是很有意思的。
下面將分別從以下幾個方面談談大型網站:
大型網站的特點
從20世紀90年代第一個Web服務的出現,現在互聯網的普及,也就短短20來年的時間。互聯網極大的改變了人們的生活、學習、生活等方方面面,筆者清晰地記得在2011年剛上大學那會,用著中國移動龜速的2G怨聲載道,到現在三大運營商大力推廣并普及4G網絡,再一次掀起了新一輪的互聯網革命,當我們享受著網頁秒開,看視頻再也不卡的暢快時,卻不知道背后的技術人員所付出的巨大努力。舉個例子,現在大家人手必裝的支付寶、淘寶等軟件無不從一個小網站發展起來的,然后逐漸成為一個大型網站。那么大型網站的特點有哪些呢?
高并發,大流量
主要是指這類網站需要面對高并發、大流量訪問。騰訊QQ的最大在線人數為1.4億(2011年數據)。
高可用
因為高并發的訪問,會使得服務器承受巨大的壓力,一旦服務器出現過載那么很可能直接掛掉,然后,就沒有然后了??。因此,高可用就顯得尤為重要,需要保證網站7*24小時不間斷提供服務。
海量數據
主要是指需要存儲、管理海量數據。百度收錄的網頁數據有數百億,有將近百萬臺服務器在提供服務。
源動力
既然大型網站是從小型網站發展起來的,那么是什么力量在推動著小網站逐漸向大型網站發展呢?
主要力量是業務的發展。從來沒有哪個網站生來就是大型網站,業務驅動技術變革,技術變革反作用于業務,從而使得網站可以支撐業務的快速發展。所以,從CEO(CTO)的角度看,網站的價值在于它所為用戶帶來了什么,而不是網站是怎么形成的。需要為用戶帶來價值是因,網站的形成是果,這個因果關系是需要認清楚的。所以,技術從來不是單純的技術(從價值的角度看),技術雖然可以解決大部分問題,但卻不一定能夠解決所有的問題。就12306網站售票的例子,如果早點使用分時段售票的做法,就沒必要投入大量的技術人員解決這個問題。業務設計也是關乎網站價值的重要方面,所以不要為了技術而技術!
演變階段
階段一:單臺服務器搞定一切
由于早期用戶量不多,所以使用一臺服務器就可以支撐業務。應用、數據、文件都在一臺機器上完成。這個階段的典型架構就是LAMP(Linux + + MySQL + PHP(Java))。搞過開發的應該都經歷過這個階段。操作系統采用Linux,使用Java或者PHP作為開發語言,使用MySQL作為數據庫,開發完后部署在上。淘寶早期的架構也是這樣的。
那會阿里因為開發資源不足,所以就購買了外國的一個網上商城,把源碼和版權都買下了(花了大概幾十萬吧),那會的淘寶的架構就是LAMP架構。
階段二:應用服務與數據隔離
隨著業務量的增長,存儲的數據越來越多而造成存儲空間的不足。這時候就把應用和數據拆分,分別部署在應用服務器、數據庫服務器和文件服務器。應用服務器由于需要處理復雜的業務邏輯,因此需要更強大的CPU,數據庫由于需要快速讀寫數據,因此需要更快的磁盤和更大的內存,文件服務器由于需要存儲大量的數據,因此需要更大容量的硬盤。需要注意的是,雖然三臺服務器承擔了不同的角色,同時也大大改善了網站的性能,但是在整個應用中,需要的服務都是通過直連的方式完成的。直連的意思是指,當需要讀寫數據庫的數據時,是直接訪問的。雖然有壓測數據表明,在不使用任何第三方組件直接使用MySQL的并發可以達到10000多。所以,如果并發數小于這個值,直連的方式也沒有什么問題。所以,如果并發數超過了10k,那么數據庫的壓力就比較大了,造成的問題就是訪問時延增大,進而影響整個網站的性能。
階段三:使用緩存改善性能
根據“二八定律”:80%的業務訪問集中在20%的數據上,也就是說這20%的數據是熱點數據,訪問頻率相比其他數據大數倍甚至更多。所以,如果把這小部分的數據緩存在內存中,用戶訪問的時候直接從內存中取,就不需要通過數據庫,從而大大降低數據庫的訪問壓力。
通常而言,緩存可以分為本地緩存和部署在分布式服務器上的遠程緩存。本地緩存存在于應用服務器所在的內存中,可能于應用數據發生爭用的情況,而遠程緩存則不會存在這種情況,因為所有的數據都是熱點數據,沒有干擾。本地緩存又可以分為瀏覽器緩存()、操作系統緩存(如CPU的L1、L2和L3)、應用服務器的緩存(本地內存中)。通常可以使用作為本地緩存、Redis或者作為分布式緩存
階段四:搭建應用服務器集群改善并發
截至目前的演變,應用服務器仍然是單兵作戰,雖然以上的演變大大改善額網站的性能,但是隨著業務量的進一步上升,單臺服務器的瓶頸就顯現出來了,因為很可能因為負載過高導致應用服務器直接掛掉。這種情況下,更好的做法是使用增加服務器的方式水平擴展,這樣就可以實現彈性伸縮,當負載過高的時候增加服務器,當負載降下來的時候,減少服務器。是不是很優雅?阿里在2012年提出的去“IOE”的原因之一就與這點有關。
IOE分別是指IBM、、EMC
雖然很優雅,但是應用服務器采用集群部署后,原來的請求過來的時候,如何知道調用哪臺服務器完成請求呢?這就需要使用到負載均衡服務器了,干嘛的呢?就是負責將請求轉發給某臺服務器。負載均衡又包括硬負載和軟負載。硬負載是硬件解決方案,比如F5,但是通常成本比較高,更常用的解決方案是軟負載,就是通常軟件實現負載均衡,比如LVS。
階段五:數據庫讀寫分離減輕數據讀寫壓力
雖然之前使用緩存將熱點數據緩存起來了,但是也存在緩存不命中的情況,這個時候又會直接訪問數據庫了,當緩存不命中的情況增大到一定規模的時候數據庫的壓力就又是一個問題了。我們知道都數據庫進行的操作無非兩種:讀和寫。由于數據庫(比如MySQL)存在事務隔離級別和鎖的機制,可能會導致讀和寫互相阻塞,那么如何實現數據庫的讀寫分離呢?目前的思路將數據庫進行主從拆分,所有的寫操作操作主庫,所有的讀操作操作從庫,對主庫的更新操作會通過同步到從庫上,從而在從庫也可以拿到最新的數據。如此一來,讀寫不再互相阻塞,性能至少提升1倍以上。就MySQL而言,主從熱備的功能可以通過cobar、mycat之類的框架來完成。
階段六:使用CDN和反向代理改善網站響應
網站的響應又一個直觀的指標(從用戶的角度)—— 訪問的快慢。這點直接關系到用戶體驗,因為如果用戶執行一個請求老半天都沒有響應,很可能就直接失去了這個用戶,然后通過口啤效應,后果很嚴重。CDN和反向代理一種提高網站響應的手段。其基本原理都是緩存。CDN是部署再網絡提供商所在的機房,當用戶發起一個請求的時候,優先從距離其較近的網絡提供商完成請求,而反向代理則是部署再網站的中心機房,當請求到達中心機房時,會首先由反向代理服務器完成請求,如果反向代理服務器存在請求的數據,那么直接返回數據給用戶。
階段七:使用分布式文件系統和分布式數據庫進一步改善讀寫壓力
當單表的數據量達到一定規模的時候,比如過千萬,即使使用數據庫索引進行優化,完成的性能提升也是有限的。因為當單表的數據量達到千萬的時候受限于執行SQL的數據庫引擎(比如MySQL的),所以需要進行分庫分表。通常的做法時根據業務進行分庫(垂直拆分),根據單表的數據量限制做分表(水平拆分)。業務分庫需要根據具體的業務場景進行確定,相對來說比較好完成,分表就不是這樣了。因為在代碼中寫的SQL就是一張表,現在要分表,那原來的SQL肯定有問題。這個可以通過merge引擎來完成。
階段八:使用NoSQL和搜索引擎優化檢索性能
使用NoSQL和搜索引擎時為了解決數據查詢的需求搜索引擎原理與實踐 源程序,比如在淘寶搜索一件商品的時候,總不能使用SQL的like進行匹配吧,效率太低!而搜索引擎可以利用倒排索引這種數據結構很好支持數據查詢。常用的解決方案時/Solr。
階段九:業務拆分讓網站維護更簡單
隨著業務場景的復雜化,將不同的業務分成不同的產品,就是把一個網站原來一個項目的情況拆分為根據不同的業務拆分為不同的項目。如果在項目中需要依賴其他項目的服務,比如在Maven工程中可以通過添加依賴的方式獲取。
階段十:抽取公共服務
這點很好理解,比如在不同的業務(項目)中都需要使用用戶管理這個業務,那么可以把這個業務抽取出來作為公共服務,需要的時候直接添加依賴即可。
技術點整理
雖然大型網站演變到現在,架構已經非常復雜,但是仍然可以歸為以下的架構模型:
前端 ——> 應用層 ——> 服務層 ——> 存儲層 ——> 后臺架構
大型網站架構要素可以總結為5點:高性能、高可用、伸縮性、可擴展性、安全性。
高性能
主要關注以下幾個指標:響應時間(一個請求從發出請求到接收到響應數據需要的時間,是網站最重要的性能指標)、并發數(網站能夠同時處理請求的請求數)、吞吐量(單位時間內系統處理的請求數,反映了網站的整體性能)。比如TPS是指每秒的事務數、QPS是指每秒的查詢數。并發數在逐漸增大的過程中,系統的吞吐量會先逐漸增加,到達一個極限后,隨著并發數的繼續增大反而下降,直至系統資源后耗盡,吞吐量為0。這是因為并發數增大的過程實際上系統資源消耗增大的過程。而在這個過程中,響應時間會先保持小幅的上升,到達吞吐量極限后,快速上升,資源耗盡后,系統失去響應。
高可用
高可用就是在網站發生故障的時候能夠迅速處理,保證網站服務依然可用、數據依然能夠被訪問。這里包括兩點:服務的高可用和數據的高可用。服務的高可用的通常處理策略是分級管理(核心業務使用更好的硬件資源)、超時設置(服務調用超時使用服務超時策略,比如繼續重試和服務調用轉移,由其他可用的服務提供服務)、異步調用(能晚則晚)、服務降級(在性能下降或者服務宕機的時候,使用拒絕服務以及關閉服務的策略,即使是失敗也要迅速返回,而不要讓請求一直hung著)、冪等性(保證在重復調用的情況下返回和調用一次的結果相同)。數據的高可用包括數據備份和失效轉移(某臺服務器宕機,能夠路由到其他機器繼續提供服務),在分布式環境,數據會被多個節點操作,如何保證數據的一致性是數據高可用的前提,這里涉及的核心技術點是CAP、BASE理論。
伸縮性
在不改變現有系統架構的前提下,僅僅通過增加或者減少機器就可以改變網站的處理能力。
可擴展性
指的是在對現有系統影響最小的情況下,系統功能的可持續擴展或者提升的能力。通常表現在應用之間較少的耦合、對需求變更敏捷響應,符合開閉原則。
安全性
保護網站不受惡意訪問和攻擊,保護網站的數據不被竊取和篡改。
技術點
下面是我整理的各個要素的核心技能點,更詳細的技能圖譜將在下篇博客中給出(思維導圖)。
高性能:分布式緩存(Redis)、異步調用(NIO/AIO + MQ(消息隊列) + JVM + 代碼優化)、HDFS
高可用:分布式、異步調用 + 服務降級 + 冪等性保證、數據備份 + 失效轉移
伸縮性:負載均衡算法、一致性hash、cobar集群、Hbase
可擴展性:分布式消息隊列(、、、Kafka)、分布式服務(dubbo、gRPC)
安全性:MD5,SHA(單項散列加密)、DES(對稱加密)、RSA,HTTPS(非對稱加密)
程序員價值觀
可以發現在大型網站的演變中每個階段需要解決的問題都是圍繞業務進行,而這點是直接與產生的價值掛鉤的。不過這都是大的方面了,因為作為一個程序員,我們更關心的技術本身以及技術所帶給我們的成長與增值空間。雖然我還不是一個有豐富經驗的程序員,但是作為程序員很重要的一點就是保持學習、保持進步。我對自己的目標是三到五年內能夠具有獨立架構設計能力,具有獨當一面的能力(包括人脈和自身能力(技能和知識儲備))。而我對自己設定的目標是在每天的上班之余堅持看書,不在于能看多少,重要的是有收獲,得到了成長。說來懺愧,這點并沒有很好的貫徹下去,但是自己以后會慢慢適應這種節奏的。
也許每天上班本來就很累,晚上下班回來還要抽空看書是痛苦的,但如果沒有這種毅力如何實現三年目標、五年目標呢?至少現在自己還年輕,有拼搏的本錢,所以就更應該好好珍惜時間,不斷地提升自我,爭取早日實現目標。
回到主題,首先需要認識到,掌握上述的技能點不是一朝一夕的,這就需要不斷在空閑時間升華自己,一點一滴積累。而且,掌握技能僅僅是第一步,真正牛逼的程序員是能夠把上述相關知識與技能進行重組,并且很好的解決業務問題,謂之“最佳實踐”。而且對每個技能點與知識一定要進行體系化學習,因為體系化的學習可以了解到技術的全貌,而不是僅僅在工作需要時就可以的。謂之技術的深度。牛逼的程序員的牛逼之處在于能夠對技術的實現細節了然于胸,這樣當系統出問題時才能迅速定位問題所在,并快速解決問題。而體系化的學習公認的最佳實踐就是看書了,所以千萬不要吝嗇買書的錢,因為買了,書的價值就在那搜索引擎原理與實踐 源程序,一切就等你去挖掘了!
我覺得可以先設立一個小目標,比如每個月至少4篇博客。道阻且長,我心向往之!!