這篇文章主要講述分佈式時代和中間件相關知識,包括服務化、HSF、Notify和TDDL。同時裏面有咱們常常碰見的編碼錯誤等相關問題,但願文章對你有所幫助!
在系統發展的過程當中,架構師的眼光相當重要,做爲程序員,只要把功能實現便可,但做爲架構師,要考慮系統的擴展性、重用性,對於這種敏銳的感受,有人說是一種「代碼潔癖」。淘寶早期有幾個架構師就具有了這種感受,周銳虹開發的Webx是一個擴展性很強的框架,行癲在這個框架上插入了數據分庫路由的模塊、Session框架等。在作淘寶後臺系統時,一樣須要這幾個模塊,行癲指導我把這些模塊單獨打成JAR包。程序員
上面說的都是比較小的複用模塊,到2006年,咱們作了一個商品類目屬性的改造,在類目中引入了屬性的概念。項目代號叫「泰山」,這是一個舉足輕重的項目,這個改變是一個劃時代的創新。數據庫
在這以前三年時間內,商品的分類都是按照樹狀一級一級的節點來分的,隨着商品數量增加,類目也變得愈來愈深、複雜。這樣,買家若是查找一件商品,就要逐級打開類目,找商品以前要弄清商品的分類。一個很嚴重的問題,例如男裝裏有T恤、T恤下面有耐克、耐克有純棉的,女裝也有T恤、T恤下面仍是有耐克、耐克下有純棉,那是先分男女裝,再分款式、品牌和材質呢?仍是先分品牌,再分款式、材質和男女裝呢?緩存
這時一燈說品牌、款式、材質等均可以叫作「屬性」,屬性是相似Tag(標籤)的一個概念,與類目相比更加靈活,這樣也縮減了類目的深度。這個思想解決了分類的難題!服務器
從系統角度來看,咱們創建了「屬性」這樣一個數據結構,因爲除了類目的子節點有屬性外,父節點也可能有屬性,因而類目屬性合起來也是一個結構化的數據對象。把它獨立出來做爲一個服務,叫作Catserver(Category Server)。跟類目屬性密切關聯的商品搜索功能獨立出來,叫作Hesper(金星)。Catserver和Hesper供淘寶的先後臺系統調用。微信
如今淘寶的商品類目屬性已是全球最大的,幾乎沒有什麼類目的商品在淘寶上找不到(除違禁品),但最初的類目屬性改造完以後,缺少屬性數據,尤爲是數碼類。從哪裏弄這些數據呢?咱們跟「中關村在線」合做,拿到了不少數據。數據結構
有了類目屬性給運營工做帶來了很大的便利,咱們知道淘寶的運營主要就是類目的運營,什麼季節推出什麼商品,都要在類目屬性上作調整,讓買家容易找到。所屬商品的賣家要編輯一次本身的商品,如冬天把羽絨衣調整到女裝一級目錄下,但隨着商品量的增加,賣家的工做量愈來愈大。架構
到了2008年,咱們研究了超市裏先後臺商品的分類,發現超市先後臺商品能夠隨季節和關聯來調整擺放場景(例如著名的啤酒和尿布的關聯),後臺倉庫裏要按照天然類目來存儲,兩者密切關聯,卻又相互分開。淘寶前臺展現的是根據運營須要擺放商品的類目和屬性。改造後的類目屬性服務取名爲Forest(森林,與類目屬性有點神似。Catserver還用於提供賣家受權、品牌服務、關鍵詞等相關服務)。類目屬性的服務化是淘寶在系統服務化方面作的第一個探索。負載均衡
雖然個別架構師具有了「代碼潔癖」,但淘寶前臺系統的業務量和代碼量仍是呈爆炸式的增加。框架
業務方總在後面催,開發人員不夠就繼續招人,招來的人根本看不懂原來的業務,只好摸索着在「合適的地方」加上一些「合適的代碼」,看看運行起來像那麼回過後,就發佈上線。異步
在這樣的惡性循環中,系統愈來愈腫,業務的耦合性愈來愈高(高內聚、低耦合),開發的效率愈來愈低。借用當時較流行的一句話:「你寫一段代碼,編譯一下能經過,半個小時過去了;編譯一下沒經過,半天就過去了。」在這種狀況下,系統出錯的機率也逐步增加,這讓開發人員苦不堪言。感受如今不少公司招實習生都是這種感受。
2007年年末的時候,研發部空降了一位從硅谷來的高管——空聞大師。他是一位溫厚的長者,他告訴咱們一切要以穩定爲中心,全部影響系統穩定的因素都要解決掉。例如:每作一個平常修改,都必須對整個系統迴歸測試一遍;多個平常修改若是放在一個版本中,要是一個功能沒有測試經過,整個系統都不能發佈。咱們把這個叫作「火車模型」,即任何一個乘客沒有上車,都不準發車。這樣作最直接的後果就是火車一直晚點,新功能上線更慢,咱們能明顯感受到業務放的不滿,壓力很是大。
如今回過頭來看,其實咱們並無理解背後的思路。正是在這種要求下,咱們不得不開始改變些東西,例如:把迴歸測試平常化,天天晚上都跑一遍整個系統的迴歸。
另外,在這種要求下,咱們不得不對這個超級複雜的系統作肢解和重構,其中複用性最高的一個模塊:用戶信息模塊開始拆分出來,咱們叫它UIC(User Information Center)。在UIC中,它只處理最基礎的用戶信息操做,例如getUserById、getUserByName等。
在另外一方面,還有兩個新興的業務對系統基礎功能的拆分也提出了要求。在那時候,咱們作了淘寶旅行(trip.taobao.com)和淘寶彩票(caipiao.taobao.com)兩個新業務,這兩個新業務在商品的展現和交易的流程上都跟主站的業務不同,機票是按照航班信息展現的,彩票是按照雙色球、數字和足球的賽程來展現的。但用到的會員功能和交易功能是與主站差很少的,當時作起來很糾結,由於若是在主站中作,會有一大半跟主站無關的東西,若是從新作一個,會有不少重複建設。
最終咱們決定再也不給主站添亂了,就另起爐竈作了兩個新的業務系統,從查詢商品、購買商品、評價反饋、查看訂單這一整個流程都從新寫了一套。如今在「個人淘寶」中查看交易記錄,還能發現「已買到的寶貝」中把機票和彩票另外列出來了,他們沒加入到普通訂單中。
當時若是已經把會員、交易、商品、評價這些模塊都拆分出來,就不用什麼都重作一遍了。
到2008年初,整個主動系統(有了機票、彩票系統以後,把原來的系統叫作主站)的容量已經達到了瓶頸,商品數在1億個以上,PV在2.5億個以上,會員數超過了5000萬個。這時Oracle的鏈接池數量都不夠用了,數據庫的容量到了極限,即便上層系統加機器也沒法繼續擴容,咱們只有把底層的基礎服務繼續拆分,從底層開始擴容,上層才能擴展,這才能容納將來三五年的增加。
因而咱們啓動了一個更大的項目,即把交易這個核心業務模塊拆分出來。
原來的淘寶交易除了跟商品管理耦合在一塊兒,還在支付寶和淘寶之間轉換,跟支付寶耦合在一塊兒,這會致使系統很複雜,用戶體驗也很很差。咱們把交易的底層業務拆分出來,叫交易中心(TradeCenter,TC),所謂底層業務,就如建立訂單、減庫存、修改訂單狀態等原子型的操做;交易的上層業務叫交易管理(TradeManager,TM)例如拍下一件普通商品要對訂單、庫存、物流進行操做,拍下虛擬商品不須要對物流進行操做,這些在TM中完成。
3.業務模塊化
類目屬性、用戶中心、交易中心,隨着這些模塊逐步拆分和服務化改造,咱們在系統架構方面也積累了很多經驗。到2008年年末就作了一個更大的項目,把淘寶全部的業務都模塊化,這是繼2004年從LAMP架構到Java架構之間的第二次脫胎換骨。
咱們對這個項目取了一個很霸氣的名字——「五彩石」(女媧煉石補天用的石頭)。這個系統重構的工做很是驚險,有人稱爲「給一架高速飛行的飛機換髮動機」。他們把淘寶的系統拆分紅了以下架構。
其中,UIC和Forest在上文已說過,TC、IC、SC分別是交易中心(Trade Center)、商品中心(Item Center)、店鋪中心(Shop Center),這些中心級別的服務只提供原子級的業務邏輯,如根據ID查找商品、建立交易、減小庫存等操做。
再往上一次是業務系統TM(Trade Manager,交易業務)、IM(Item Manager,商品業務)、SM(Shop Manager,後來更名叫SS,即Shop System,店鋪業務)、Detail(商品詳情)。
拆分以後,系統之間的交互關係變得很是複雜。
系統這麼拆分的好處顯而易見,拆分以後每一個系統能夠單獨部署,業務簡單,方便擴容;有大量可重用的模塊便於開發新的業務;可以作到專人專事,讓技術人員更加專一於某一個領域。
這樣要解決的問題也很明顯,拆分後,系統之間仍是必需要打交道的,越往底層的系統,調用它的客戶越多,這要求底層系統必須具備超大規模的容量和很是高的可用性。
另外,拆分以後的系統如何通訊?這裏須要兩種中間件系統,一種是實時調用的中間件(淘寶的HSF,高性能服務框架),一種是異步消息通知的中間件(淘寶的Notify)。另外,一個須要解決的問題是用戶在A系統登陸後,到B系統的時候,用戶的登陸信息怎麼保存?這又設計一個Session框架。再者,還有一個軟件工程方面的問題,這麼多層的一套系統,怎麼去測試它?
1.HSF
其實互聯網網站發展過程相似於超市經營(此處省略超市銷售收銀的例子,能夠想象下沃爾瑪排隊購物付款的場景吧),只是在技術層面用其餘名詞來表達而已,例如:有集羣、分工、負載均衡、根據QoS分配資源等。
集羣:全部收銀員提供的都是收銀功能,每一個收銀員均可以完成收款,能夠認爲全部的收銀員構成了一個集羣。互聯網集羣會受限於調度、數據庫、機房等。
分工:收銀員和打掃衛生的人分開,這種分工容易解決,而這種分工在互聯網中是一項重要而複雜的技術,涉及的主要有按功能和數據庫的不一樣拆分系統等。如何拆分和拆分後如何交互是須要面臨的兩個挑戰。隱藏會有高性能通訊框架、SOA平臺、消息中間件、分佈式數據層等基礎產品的誕生。
負載均衡:讓每一個收銀臺排隊差很少長,設立小件通道、團購通道、VIP通道等,這些均可認爲是集羣帶來的負載均衡的問題,從技術層面上實現天然比生活中複雜得多。
根據QoS(Quality of Service,服務質量)分配資源:部分員工僅在晚上加班的機制在生活中不難實現,但對互聯網應用而言,就是一件複雜並且極具挑戰的事。
並且生活中面對用戶增加的狀況下,想出這些招應該不難。不過要掌握以上四點涉及的技術就至關複雜了,並且互聯網中涉及的其餘不少技術尚未在這個例子中展示出來。例如緩存、CDN等優化手段;運轉情況監測、功能降級、資源劣化、流控等可用性手段;自建機房、硬件組裝等成本控制手段。所以,構建一個互聯網網站確實是不容易的,技術含量十足,固然,經營一家超市也不簡單。
服務拆分以後,如何取得我須要的服務呢?
在「電視機」上,把每一個集羣能提供的服務顯示出來。你不須要關心哪一個人爲你服務,當你有須要的時候,頭頂的電視機會告訴你哪一個服務在哪一個區域。當你去到這個區域時,系統會給你找到一個最快的服務通道。
這就是HSF(High-Speed Service Framework)的設計思想:
服務的提供者啓動時經過HSF框架向ConfigServer(相似超市的電視機)註冊服務信息(接口、版本、超時時間、序列化方式等),ConfigServer上定義了全部可供調用的服務(同一個服務也可能有不一樣的版本);
服務調用者啓動時向ConfigServer註冊對哪些服務感興趣(接口、版本),當服務提供者的信息變化時,ConfigServer向趕興趣的服務調用者推送新的服務信息列表;調用者在調用時則根據服務信息的列表直接訪問相應的服務提供者,無須通過ConfigServer。
咱們注意ConfigServer並不會把服務提供者的IP地址推送給服務的調用者,HSF框架會根據負載情況來選擇具體的服務器,返回結果給調用者,這不只統一了服務調用的方式,也實現了「軟負載均衡」。平時ConfigServer經過和服務提供者的心跳來感應服務提供者的存活狀態。
在HSF的支持下,服務集羣對調用者來講是「統一」的,服務之間是「隔離」的,這保證了服務的擴展性和應用的統一性。再加上HSF自己提供的「軟負載均衡」,服務層對應用層來講就是一片「私有云」了。
HSF框架以SAR包的方式部署到Jboss、Jetty或Tomcat下,在應用啓動時,HSF(High-Speed Service Framework,在開發團隊內部有一些人稱HSF爲「好舒服」)服務隨機啓用。HSF旨在爲淘寶的應用提供一個分佈式的服務框架,HSF從分佈式應用層面以及統一的發佈/調用方式層面爲你們提供支持,更容易地開發分佈式應用或使用公用功能模塊,而不用考慮分佈式領域中的各類細節技術,例如:遠程通信、性能損耗、調用的透明化、同步異步調用的問題。
HSF是一個分佈式的標準Service方式的RPC(RemoteProcedure Call Protocol,遠程過程調用協議)框架。Service的定義基於OSGI的方式,通信層採用TCP/IP協議。
HSF系統目前天天承擔300億次以上的服務調用,一些讀者可能會疑問:既然淘寶的服務化是漸進式的,那麼在HSF出現以前,系統之間的調用採用什麼方式呢?
這個有點「五花八門」。對於類目的調用方式是Forest打包成一個JAR包,在應用啓動時裝載到內存中,僅這個JAR包所佔用的內存就有800MB之多(由於淘寶的類目數據龐大),對於當時通常只有2GB內存的開發機來講,加載完類目信息後,機器運行速度就很是慢。對於用戶信息(UIC)來講,一開始調用方式是Hessian接口,還有一些系統是經過WebService、Socket甚至是HTTP請求來相互調用的。
每種調用方式都涉及各類超時、信息的加解/密、參數的定義等問題,因而可知,在沒有HSF以前,系統之間的調用是錯綜複雜的。而隨着系統拆分得愈來愈多,必須由一個統一的中間層來處理這種問題,HSF就是在這種背景下誕生的。
2.Notify
HSF解決了服務調用的問題,咱們再提出一個很早就說過的問題:用戶在銀行的網關付錢後,銀行須要通知到支付寶,但銀行的系統不必定能發出通知;若是通知發出了,不必定能通知到;若是通知到了,不必定不重複通知一遍。
這個情況在支付寶持續了很長時間,很是痛苦。支付寶從淘寶剝離出來時,淘寶和支付寶之間的通訊也面臨一樣的問題,支付寶架構師魯肅提出用MQ(Message Queue)的方式來解決這個問題,我負責淘寶這邊讀取消息的模塊。但消息數量上來後,經常形成擁堵,消息的順序也會出錯,系統掛掉消息也會掛掉。
而後魯肅提出作一個系統框架上的解決方案,把要發出的通知存到數據庫中,若是實時發送失敗,再用一個時間程序來週期性地發送這些通知,系統記錄下消息中間狀態和時間戳,這樣就保證了消息必定能發出,也必定能通知到,且通知帶有時間順序,甚至能夠實現失去性的操做。
(PS:這個技術感受之前作Android相似微信的隨手拍軟件時很是適用)
在「千島湖」項目和「五彩石」項目後,淘寶系統拆分紅了不少個,他們之間也須要相似的通知。例如,拍下一件商品,在交易管理系統中完成時,它須要通知商品管理系統減小庫存,同時旺旺服務系統發送旺旺提醒,通知物流系統上門取貨,通知SNS系統分享訂單,通知公安局的系統這是騙子等等。
用戶一次請求,在底層系統可能產生10次的消息通知。這一大堆的通知信息是異步調用的(若是同步,系統耦合在一塊兒就達不到拆分的目的),這些消息通知須要一個強大的系統提供支持,從消息的數量級上看,比支付寶和淘寶之間的消息量又上了一個層次,因而按照相似的思路,一個更增強大的消息中間件系統就誕生了,它的名字叫作Notify。
Notify是一個分佈式的消息中間件系統,支持消息的訂閱、發送和消費,其架構圖以下所示:
NotifyServer在ConfigServer上註冊消息服務,消息的客戶端經過ConfigServer訂閱消息服務。某個客戶端調用NotifyServer發送一條消息,NotifyServer負責把消息發送到全部訂閱這個消息的客戶端(參照HSF圖)。
爲了保證消息必定能發出,且對方必定能收到,消息數據自己就須要記錄下來,這些信息存放在數據庫中。因爲消息具備中間狀態(已發送、未發送等),應用系統經過Notify能夠實現分佈式事物——BASE(基本可用Basically Available、軟狀態Soft State、最終一致Eventually Consistent)。
NotifyServer能夠水平擴展,NotifyClient也能夠水平擴展,數據庫也能夠水平擴展。從理論上講,這個消息系統的吞吐量時沒有上限的,如今Notify系統天天承載了淘寶10億次以上的消息通知。
下圖展現了建立一筆交易後,TC(交易中心)向Notify發送一條消息,後續Notify所完成的一系列消息通知。
3.TDDL
有了HSF和Notify的支持,在應用級別中,整個淘寶網的系統能夠拆分了,還有一個制約系統規模的更重要的因素就是數據庫,也必須拆分。
前面講過淘寶很早就對數據進行過度庫的處理,上層系統鏈接多個數據庫,中間有一個叫作DBRoute的路由來對數據進行統一訪問。DBRoute對數據進行多庫的操做、數據的整合,讓上層系統像操做一個數據庫同樣操做多個庫。隨着數據量的增加,對於庫表的分發有了更高的要求。例如,你的商品數據到了百億級別時,任何一個庫都沒法存放了,因而分紅2個、4個…1024個、2048個。分紅這麼多,數據能存放了,那怎麼查詢它?
這時候,數據查詢的中間件就要可以承擔這個重任了,它對上層來講,必須像查詢一個數據庫同樣來查詢數據,還要想查詢一個數據庫同樣快(每條查詢在幾毫秒內完成),TDDL就承擔了這樣一個工做。
另外,加上數據的備份、複製、主備切換等功能,這一套系統都在TDDL中完成。在外面有些系統也用DAL(數據訪問層)這個概念來命名這個中間件。TDDL實現了下面三個主要的特性:
1).數據訪問路由——將針對數據的讀寫請求發送到最適合的地方
2).數據的多向非對稱複製——一次寫入,多點讀取
3).數據存儲的自由擴展——再也不受限於單臺機器的容量瓶頸與速度瓶頸,平滑遷移
下圖展現了TDDL所處的位置:
你們逐漸發現,若是按照業務的發展規模和速度,那麼使用高端存儲和小型機的Oracle存儲的成本將難以控制,因而下降成本就成了必然。如何可以在不影響業務正常發展的前提下,解決成本問題呢?
「對一部分數據庫使用MySQL」,DBA們的決策是這樣,因而分佈式數據層的重擔就落到了華黎的頭上。當時的需求以下:對外統一一切數據訪問、支持緩存和文件存儲系統、可以在Oracle和MySQL之間自由切換、支持搜索引擎。
那麼,如何實現分佈式Join(鏈接)?(跨節點後簡單Join就會變成M*N臺機器的合併,代價太大)如何實現高速多維度查詢?如何實現分佈式事務?
因而動手咱們本身作,名字叫Taobao Distributed Data Layer(TDDL,外號「頭都打了」),學習開源的Amoeba Proxy。這就是TDDL 1.0時代。
粗略統計下來,TDDL已經走過了4年時間,知足了近700個業務應用的使用需求。其中有交易商品評價用戶等核心數據,也有不那麼有名的中小型應用。量變產生質變,如何可以更好地幫助這些業務以更低的成本完成業務需求,將成爲數據層將來最重要的挑戰。
最後但願文章對你有所幫助,若是文章有不足或錯誤的地方,還請海涵!文章寫到此處,感受讀後感仍是會應該以精簡爲主,下次寫書籍讀後感儘可能寫成一篇,而不是大量的摘抄原文。但願你們購買原書看看,很是不錯~