一應用無狀态(淘寶session架構)
俗話說,一個系統的伸縮性的好壞取決于應用的狀态如何管理。為什麼這麼說呢?咱們試想一下,假如我們在session中儲存了大量與用戶端的狀态信 息的話,那麼當儲存狀态資訊的server當機的時候,我們怎麼辦?通常來說,我們都是通過叢集來解決這個問題,而通常 所說的叢集,不僅有負載均衡,更重要的是要有失效恢複failover,比如tomcat采 用的叢集節點廣播複制,jboss采 用的配對複制等session狀 态複制政策,但是叢集中的狀态恢複也有其缺點,那就是嚴重影響了系統的伸縮性,系統不能通過增加更多的機器來達到良好的水準伸縮,因為叢集節點間session的 通信會随着節點的增多而開銷增大,是以要想做到應用本身的伸縮性,我們需要保證應用的無狀态性,這樣叢集中的各個節點來說都是相同的,進而是的系統更好的 水準伸縮。
OK, 上面說了無狀态的重要性,那麼具體如何實作無狀态呢?此時一個session架構就會發揮作用了。幸運的是淘 寶已經具有了此類架構。淘寶的session架構采用的是client cookie實作,主要将狀态 儲存到了cookie裡 面,這樣就使得應用節點本身不需要儲存任何狀态資訊,這樣在系統使用者變多的時候,就可以通過增加更多的應用節點來達到水準擴充的目的.但 是采用用戶端cookie的 方式來儲存狀态也會遇到限制,比如每個cookie一般不能超過4K的大小,同時很多浏覽器都限制一個站點最 多儲存20個cookie.淘 寶cookie框 架采用的是“多值cookie”, 就是一個組合鍵對應多個cookie的 值,這樣不僅可以防止cookie數 量超過20, 同時還節省了cookie存 儲有效資訊的空間,因為預設每個cookie都會有大約50個位元組的元資訊來描述cookie。
除 了淘寶目前的session框 架的實作方式以外,其實集中式session管理來完成,說具體點就是多個無狀态的應用節點連接配接一個session 服 務器,session服 務器将session保 存到緩存中,session服 務器後端再配有底層持久性資料源,比如資料庫,檔案系統等等。
二有效使用緩存(Tair)
做網際網路應用的兄弟應該都清楚,緩存對于一個網際網路應用是多麼的重要,從浏覽器緩存,反向代理緩存,頁面緩存,局部頁面緩存,對象緩存等等都是緩存應用的場 景。
一般來說緩存根據與應用程式的遠近程度不同可以分為:local cache 和remote cache。 一般系統中要麼采用local cache,要麼采用remote cache,兩者混合使用的話對 于local cache和remote cache的資料一緻性處理會變 大比較麻煩.
在大部分情況下,我 們所說到的緩存都是讀緩存,緩存還有另外一個類型:寫緩存. 對 于一些讀寫比不高,同時對資料安全性需求不高的資料,我們可以将其緩存起來進而減少對底層資料庫的通路,比如 統計商品的通路次數,統 計API的 調用量等等,可 以采用先寫記憶體緩存然後延遲持久化到資料庫,這樣可以大大減少對資料庫的寫壓力。
OK, 我以店鋪線的系統為例,在使用者浏覽店鋪的時候,比如店鋪介紹,店鋪交流區頁面,店鋪服務條款頁面,店鋪試衣間頁面,以及店鋪内搜尋界面這些界面更新不是非 常頻繁,是以适合放到緩存中,這樣可以大大減低DB的負載。另外寶貝詳情頁面相對也更新比較 少,是以也适合放到緩存中來減低DB負載。
三 應用拆分(HSF)
首 先,在說明應用拆分之前,我們先來回顧一下一個系統從小變大的過程中遇到的一些問題,通過這些問題我們會發現拆分對于建構一個大型系統是如何的重要。
系 統剛上線初期,使用者數并不多,所有的邏輯也許都是放在一個系統中的,所有邏輯跑到一個程序或者一個應用當中,這個時候因為比較使用者少,系統通路量低,是以 将全部的邏輯都放在一個應用未嘗不可。但是,兄弟們都清楚,好景不長,随着系統使用者的不斷增加,系統的通路壓力越來越多,同時随着系統發展,為了滿足使用者 的需求,原有的系統需要增加新的功能進來,系統變得越來越複雜的時候,我們會發現系統變得越來越難維護,難擴充,同時系統伸縮性和可用性也會受到影響。那 麼這個時候我們如何解決這些問題呢?明智的辦法就是拆分(這也算是一種解耦),我們需要将原來的系統根據一定的标準,比如業務相關性等分為不同的子系統, 不同的系統負責不同的功能,這樣切分以後,我們可以對單獨的子系統進行擴充和維護,進而提高系統的擴充性和可維護性,同時我們系統的水準伸縮性scale out大 大的提升了,因為我們可以有針對性的對壓力大的子系統進行水準擴充而不會影響到其它的子系統,而不會像拆分以前,每次系統壓力變大的時候,我們都需要對整 個大系統進行伸縮,而這樣的成本是比較大的,另外經過切分,子系統與子系統之間的耦合減低了,當某個子系統暫時不可用的時候,整體系統還是可用的,進而整 體系統的可用性也大大增強了。
因 此一個大型的網際網路應用,肯定是要經過拆分,因為隻有拆分了,系統的擴充性,維護性,伸 縮性,可用性才會變的更好。但是拆分也給系 統帶來了問題,就是子系統之間如何通信的問題,而具體的通信方式有哪些呢?一般有同步通信和異步通信,這裡我們首先來說下同步通信,下面的主題“消息系 統”會說到異步通信。既然需要通信,這個時候一個高性能的遠端調用架構就顯得非常總要啦,是以咱們淘寶也有了自己的HSF框 架。
上 面所說的都是拆分的好處,但是拆分以後必然的也會帶來新的問題,除了剛才說的子系統通信問題外,最值得關注的問題就是系統之間的依賴關系,因為系統多了, 系統的依賴關系就會變得複雜,此時就需要更好的去關注拆分标準,比如能否将一些有依賴的系統進行垂直化,使得這些系統的功能盡量的垂直,這也是目前淘寶正 在做的系統垂直化,同時一定要注意系統之間的循環依賴,如果出現循環依賴一定要小心,因為這可能導緻系統連鎖啟動失敗。
OK, 既然明白了拆分的重要性,我們看看随着淘寶的發展,淘寶本身是如何拆分系統的。
首 先我們來看以下這個圖:

從 上面的圖可以看出淘寶系統的一個演變過程,在這個演變的過程中,我們所說的拆分就出現V2.2和V3.0之 間。在V2.2版 本中,淘寶幾乎所有的邏輯都放在(Denali)系統中,這樣導緻的問題就是系統擴充和修改非常麻煩,并且更加緻命的是随 着淘寶業務量的增加,如果按照V2.2的架構已經沒有辦法支撐以後淘寶的快速發展,是以大家決定對整個系統進行拆分,最 終V3.0版 本的淘寶系統架構圖如下:
從 上圖可以看出V3.0版 本的系統對整個系統進行了水準和垂直兩個方向的拆分,水準方向上,按照功能分為交易,評價,使用者,商品等系統,同樣垂直方向上,劃分為業務系統,核心業務 系統以及以及基礎服務,這樣以來,各個系統都可以獨立維護和獨立的進行水準伸縮,比如交易系統可以在不影響其它系統的情況下獨立的進行水準伸縮以及功能擴 展。
從上面可以看出,一個大型系統要想變得可維 護,可擴充,可伸縮,我們必須的對它進行拆分,拆分必然也帶來系統之間如何通信以及系統之間依賴管理等問題,關于通信方面,淘寶目前獨立開發了自己的高性 能服務架構HSF, 此架構主要解決了淘寶目前所有子系統之間的同步和異步通信(目前HSF主要用于同步場合,FutureTask方 式的調用場景還比較少)。至于系統間的依賴管理,目前淘寶還做的不夠好,這應該也是我們以後努力解決的問題。
四資料庫拆分(TDDL)
在 前面“應用拆分”主題中,我們提到了一個大型網際網路應用需要進行良好的拆分,而那裡我們僅僅說了”應用級别”的拆 分,其實我們的網際網路應用除了應用級别的拆分以外,還有另外一個很重要的層面就是存儲如何拆分的。是以這個主題主要涉及到如何對存儲系統,通常就是所說的RDBMS進 行拆分。
好 了,确定了這個小節的主題之後,我們回顧一下,一個網際網路應用從小變大的過程中遇到的一些問題,通過遇到的問題來引出我們拆分RDBMS的 重要性。
系 統剛開始的時候,因為系統剛上線,使用者不多,那個時候,所有的資料都放在了同一個資料庫中,這個時候因為使用者少壓力小,一個資料庫完全可以應付的了,但是 随着營運那些哥們辛苦的呐喊和拼命的推廣以後,突然有一天發現,oh,god,使用者數量突然變多了起來,随之而 來的就是資料庫這哥們受不了,它終于在某一天大家都和惬意的時候挂掉啦。此時,咱們搞技術的哥們,就去看看究竟是啥原因,我們查了查以後,發現原來是資料 庫讀取壓力太大了,此時咱們都清楚是到了讀寫分離的時候,這個時候我們會配置一個server為master節 點,然後配幾個salve節 點,這樣以來通過讀寫分離,使得讀取資料的壓力分攤到了不同的salve節點上面,系統終于又恢複了正常,開 始正常運作了。但是好景還是不長,有一天我們發現master這哥們撐不住了,它負載老高了,汗 流浃背,随時都有翹掉的風險,這個時候就需要咱們垂直分區啦(也就是所謂的分庫),比如将商品資訊,使用者資訊,交易資訊分别存儲到不同的資料庫中,同時還 可以針對商品資訊的庫采用master,salve模式,OK, 通過分庫以後,各個按照功能拆分的資料庫寫壓力被分擔到了不同的server上面,這樣資料庫的壓力終于有恢複 到正常狀态。但是是不是這樣,我們就可以高枕無憂了呢?NO,這個NO, 不是我說的,是前輩們通過經驗總結出來的,随着使用者量的不斷增加,你會發現系統中的某些表會變的異常龐大,比如好友關系表,店鋪的參數配置表等,這個時候 無論是寫入還是讀取這些表的資料,對資料庫來說都是一個很耗費精力的事情,是以此時就需要我們進行“水準分區”了(這就是俗話說的分表,或者說sharding).
OK,上 面說了一大堆,無非就是告訴大家一個事實“資料庫是系統中最不容易scale out的一層”,一個大型的網際網路 應用必然會經過一個從單一DB server,到Master/salve,再到垂直分區(分 庫),然後再到水準分區(分表,sharding)的過程,而在這個過程中,Master/salve 以 及垂直分區相對比較容易,對應用的影響也不是很大,但是分表會引起一些棘手的問題,比如不能跨越多個分區join查 詢資料,如何平衡各個shards的 負載等等,這個時候就需要一個通用的DAL架構來屏蔽底層資料存儲對應用邏輯的影響,使得底層資料的通路對應用透明化。
拿 淘寶目前的情況來說,淘寶目前也正在從昂貴的高端存儲(小型機+ORACLE)切換到MYSQL,切 換到MYSQL以 後,勢必會遇到垂直分區(分庫)以及水準分區(Sharding)的問題,是以目前淘寶根據自 己的業務特點也開發了自己的TDDL架構,此架構主要解決了分庫分表對應用的透明化以及異構資料庫之間的資料複制。
五異步通信(Notify)
在”遠 程調用架構”的 介紹中,我 們說了一個大型的系統為了擴充性和伸縮性方面的需求,肯定是要進行拆分,但是 拆分了以後,子 系統之間如何通信就成了我們首要的問題,在”遠端調用架構”小節 中,我 們說了同步通信在一個大型分布式系統中的應用,那麼這一小節我們就來說說異步通信.好了,既 然說到了異步通信,那 麼”消 息中間件”就 要登場了,采 用異步通信這其實也是關系到系統的伸縮性,以及最大化的對各個子系統進行解耦.
說 到異步通信,我們需要關注的一點是這裡的異步一定是根據業務特點來的,一定是針對業務的異步,通常适合異步的場合是一些松耦合的通信場合,而對于本身業務 上關聯度比較大的業務系統之間,我們還是要采用同步通信比較靠譜。
OK,那 麼下一步我們說說異步能給系統帶來什麼樣子的好處。首先我們想想,假如系統有A和B兩個 子系統構成,假如A和B是 同步通信的話,那麼要想使得系統整體伸縮性提高必須同時對A和B進行 伸縮,這就影響了對整個系統進行scale out.其次,同步調用還會影響到可用性,從數學推理的角度來說,A同 步調用B, 如果A可 用,那麼B可 用,逆否命題就是如果B不 可用,那麼A也 不可用,這将大大影響到系統可用性,再次,系統之間異步通信以後可以大大提高系統的響應時間,使得每個請求的響應時間變短,進而提高使用者體驗,是以異步在 提高了系統的伸縮性以及可用性的同時,也大大的增強了請求的響應時間(當然了,請求的總體處理時間也許不會變少)。
下 面我們就以淘寶的業務來看看異步在淘寶的具體應用。交易系統會與很多其它的業務系統交 互,如果在一次交易過程中采用同步調用的話,這就要求要向交易成功,必須依賴的所有系統都可用,而如果采用異步通信以後,交易系 統借助于消息中間件Notify和 其它的系統進行了解耦,這樣以來當其它的系統不可用的時候,也不會影響到某此交易,進而提高了系統的可用性。
六非結構化資料存儲( TFS,NOSQL)
在 一個大型的網際網路應用當中,我們會發現并不是所有的資料都是結構化的,比如一些配置檔案,一個使用者對應的動态,以及一次交易的快照等資訊,這些資訊一般不 适合儲存到RDBMS中, 它們更符合一種Key-value的 結構,另外還有一類資料,資料量非常的大,但是實時性要求不高,此時這些資料也需要通過另外的一種存儲方式進行存儲,另外一些靜态檔案,比如各個商品的圖 片,商品描述等資訊,這些資訊因為比較大,放入RDBMS會引起讀取性能問題,進而影響到其它 的資料讀取性能,是以這些資訊也需要和其它資訊分開存儲,而一般的網際網路應用系統都會選擇把這些資訊儲存到分布式檔案系統中,是以淘寶目前也開發了自己的 分布式檔案系統TFS,TFS目 前限制了檔案大小為2M, 适合于一些小于2M數 據的存放。
随 着網際網路的發展,業界從08年 下半年開始逐漸流行了一個概念就是NOSQL。我們都知道根據CAP理論,一緻性,可用性和分區容錯性3者 不能同時滿足,最多隻能同時滿足兩個,我們傳統的關系資料采用了ACID的事務政策,而ACID的 事務政策更加講究的是一種高一緻性而降低了可用性的需求,但是網際網路應用往往對可用性的要求要略高于一緻性的需求,這個時候我們就需要避免采用資料的ACID事 務政策,轉而采用BASE事 務政策,BASE事 務政策是基本可用性,事務軟狀态以及最終一緻性的縮寫,通過BASE事務政策,我們可以通過最終一緻性來提 升系統的可用性,這也是目前很多NOSQL産品所采用的政策,包括facebook 的cassandra,apache hbase,google bigtable等,這些産品非常适合一些非結構化的資料,比如key-value形 式的資料存儲,并且這些産品有個很好的優點就是水準伸縮性。目前淘寶也在研究和使用一些成熟的NOSQL産品。
七監控、預警系統
對于大型的系統 來說,唯一可靠的就是系統的各個部分是不可靠。
因 為一個大型的分布式系統中勢必會涉及到各種各樣的裝置,比如網絡交換機,普通PC機,各種型号的網卡,硬碟,記憶體等等,而這 些東東都在數量非常多的時候,出現錯誤的機率也會變大,是以我們需要時時刻刻監控系統的狀态,而監控也有粒度的粗細之分,粒度粗一點的話,我們需要對整個 應用系統進行監控,比如目前的系統網絡流量是多少,記憶體使用率是多少,IO,CPU的 負載是多少,服務的通路壓力是多少,服務的響應時間是多少等這一系列的監控,而細粒度一點的話,我們就需對比如應用中的某個功能,某個URL的 通路量是多,每個頁面的PV是 多少,頁面每天占用的帶寬是多少,頁面渲染時間是多少,靜态資源比如圖檔每天占用的帶寬是多少等等進行進一步細粒度的監控。是以一個監控系統就變得必不可 少了。
前 面說了一個監控系統的重要性,有了監控系統以後,更重要的是要和預警系統結合起來,比如當某個頁面通路量增多的時候,系統能自動預警,某台Server的CPU和 記憶體占用率突然變大的時候,系統也能自動預警,當并發請求丢失嚴重的時候,系統也能自動預警等等,這樣以來通過監控系統和預警系統的結合可以使得我們能快 速響應系統出現的問題,提高系統的穩定性和可用性。
八配置統一管理
一 個大型的分布 式應用,一般都是有很多節點構成的,如果每次一個新的節點加入都要更改其它節點的配置,或者每次删除一個節點也要更改配置的話,這樣不僅不利于系統的維護 和管理,同時也更加容易引入錯誤。另外很多時候叢集中的很多系統的配置都是一樣的,如果不進行統一的配置管理,就需要再所有的系統上維護一份配置,這樣會 造成配置的管理維護很麻煩,而通過一個統一的配置管理可以使得這些問題得到很好的解決,當有新的節點加入或者删除的時候,配置管理系統可以通知各個節點更 新配置,進而達到所有節點的配置一緻性,這樣既友善也不會出錯。