StubHub架構(gòu)揭秘:世界上最大的票務(wù)市場到底有多復(fù)雜?
譯文【51CTO快譯】StubHub這個令人關(guān)注的架構(gòu)之所以值得剖析,是因為作為票務(wù)做市商,它從事的行業(yè)不同于我們通常所考慮的行業(yè)。
StubHub規(guī)模大得驚人,每年以20%的速度發(fā)展,每小時提供80萬個復(fù)雜頁面,每年出售的各種票多達(dá)500萬張,每小時處理200萬次API(應(yīng)用編程接口)調(diào)用。
而票務(wù)行業(yè)來得異常復(fù)雜。StubHub的流量很復(fù)雜。其流量具有突發(fā)性,主要圍繞不可預(yù)測的比賽結(jié)果、文體活動、比賽時間表和賽季。這行當(dāng)涉及許多的錢,涉及許多不同的演藝人員,涉及許多復(fù)雜的業(yè)務(wù)流程。而StubHub有幾個互為補充但全然不同的業(yè)務(wù)部分:它有一個廣告服務(wù)器組件(為ESPN等網(wǎng)站提供廣告)、豐富的交互式用戶界面以及實時票務(wù)市場組件。
我最感興趣的是,StubHub怎樣把曾經(jīng)高度人性化的物理領(lǐng)域(各種票、銷售點系統(tǒng)、聯(lián)邦快遞送貨、買賣雙方和錢財)搬入到數(shù)字領(lǐng)域。它實現(xiàn)這一切的手段是,與美國職業(yè)棒球大聯(lián)盟等組織進(jìn)行全面深入的電子集成,并借助生命周期總線(Lifecycle Bus)讓復(fù)雜的業(yè)務(wù)流程與應(yīng)用領(lǐng)域隔離開來。
由于StubHub既要向前發(fā)展,又要應(yīng)對早期發(fā)布擴(kuò)大業(yè)務(wù)的功能特性是優(yōu)先項目時構(gòu)建的遺留系統(tǒng),這個令人關(guān)注的問題顯得更加困難了。下面看看StubHub是如何成功做到的。
本文來源
■StubHub架構(gòu)主管Charlie Fineman在QCon大會上的演講:《StubHub:為擴(kuò)展性和創(chuàng)新而設(shè)計,打造世界上最大的票務(wù)市場》
經(jīng)營模式
■StubHub好比是票務(wù)市場的電子港灣(eBay)。為買票賣票雙方提供了一個市場。它與世界上最大的票務(wù)公司特瑪捷公司(Ticketmaster)不一樣。
■第三方保管模式用來為買賣雙方提供信任和安全機制。信用卡在StubHub存檔起來,只有訂單確認(rèn)為票已收到后,買方才從信用卡上轉(zhuǎn)賬。
■門票不是普通商品。比如說,買方想要特定的門票,而不是露天看臺座椅。門票數(shù)量有限,門票也不可以延期交貨。面對不斷變化的市場形勢,賣方不斷更新價格和數(shù)量。這是個非常活躍的市場。
統(tǒng)計數(shù)字
■每年500萬筆訂單。
■200萬張待售門票。
■門票涉及大約4500場文體活動。美國職業(yè)棒球大聯(lián)盟季后賽和美國橄欖球超級杯大賽是銷售最旺的時期。
■銷售幅度每年增長20%。
■每小時提供60萬至80萬個復(fù)雜頁面。季后賽期間,猛增到每小時100萬個頁面。
■在美國觀看比賽的黃金時段(每晚10點至12點)的短暫時間期間,流量的突發(fā)性非常強。比如說,季后賽結(jié)束后,會出現(xiàn)人們瘋狂購買下一個賽季門票的情況。
■來自附屬組織的API調(diào)用每小時多達(dá)200萬次。
■24至36名工程師。
■這是高度人性化的行業(yè)。過去,支持電話與交易比是1:1,但現(xiàn)在情況好多了。工作人員最主要的工作是客戶服務(wù)和后臺業(yè)務(wù)運營支持。
平臺
■Java
■Cold Fusion(遺留平臺)
■ActiveMQ
■SEDA(分階段事件驅(qū)動架構(gòu))
■Lucene/Solr
■Jboss
■Memcache
■Infiniband—連接至存儲區(qū)域網(wǎng)絡(luò)(SAN)的高速網(wǎng)絡(luò)
■XSL
■甲骨文的高級隊列(Advanced Queuing)
■TeamWorks—IBM工作流程構(gòu)建器
■Splunk
■Apache HttpClient
■Log4j(使用消息格式)
■Tapestry
架構(gòu)
■購買門票有三個來源:互聯(lián)網(wǎng)、銷售點系統(tǒng)和批量上傳。批量上傳允許多張門票上傳到系統(tǒng)。
■Manager層在Ticket數(shù)據(jù)庫上提供了一種業(yè)務(wù)對象抽象機制。它負(fù)責(zé)調(diào)控與訂票系統(tǒng)的所有聯(lián)系。
■訂票系統(tǒng)因買賣雙方的活動和文體活動天生具有突發(fā)性的流量而擁堵。
■活躍市場會使得使用移動設(shè)備的客戶無法及時了解系統(tǒng)現(xiàn)狀,所以買方應(yīng)對的是舊數(shù)據(jù)。
■兩個數(shù)據(jù)泵(data pump)將數(shù)據(jù)從Tickets數(shù)據(jù)庫抽取到內(nèi)外系統(tǒng):My Account、Find和Public Feed。My Account是用戶賬戶的接口。Find是一項搜索功能。Public Feeds則支持ESPN和電子港灣等網(wǎng)站。
■Internal Feed:含有用于儀表板的敏感信息,比如賬戶信息,包括賣方是誰、銷售情況如何、銷售速度和熱圖(heat map)等。它還提供主頁中基于敏感市場數(shù)據(jù)的部分,比如什么熱銷,這些是StubHub不想拿來與公眾共享的。
■External Feed(LCS)—通過該Feed為ESPN等廣告商提供數(shù)據(jù)來源。廣告由IP地址實現(xiàn)地理映射。
■LCS(列表目錄服務(wù))
■這里先說聲抱怨,幻燈片有點錯誤,很難把演講者與演講文稿對應(yīng)起來。所有錯誤都怪我。
■觸發(fā)器用來確保修改表格及時更新;數(shù)據(jù)庫一出現(xiàn)變更,這些變更內(nèi)容就會出現(xiàn)在表格中。
■變更數(shù)據(jù)捕獲(Change Data Capture)作業(yè)不斷查詢變更,并把消息注入到ActiveMQ中介。這是路由傳送的第一道,含有較小的有效載荷:對象編號、對象類型和變更日期。
■變更數(shù)據(jù)傳送到Master,這是數(shù)據(jù)中心之間進(jìn)行復(fù)制的基本機制。輔助數(shù)據(jù)中心訂閱這些主題,這就是數(shù)據(jù)中心之間復(fù)制數(shù)據(jù)的方式。
■一旦在Master中,數(shù)據(jù)被注入到SEDA隊列,進(jìn)行處理(稍后會有詳細(xì)介紹)。
■并不使用Manager,因為存在不使用Manager、直接進(jìn)入到數(shù)據(jù)庫的許多遺留系統(tǒng),所以數(shù)據(jù)庫是分發(fā)變更內(nèi)容的常見點。
■大部分廣告是Flash廣告,但有些使用HTML渲染。
■購票體驗得到LCS的支持,比如從體育館的交互圖形中選擇門票。Solr使得添加諸如此類的新功能特性變得很容易。
■SEDA(分階段事件驅(qū)動架構(gòu))在Master中的使用
■SEDA是減輕負(fù)擔(dān)的一種方法。從資源管理的角度來看,它對StubHub來說行之有效。其想法是,把工作負(fù)載分解成足夠小的部分,那樣這些細(xì)分后的工作負(fù)載不會竊取其他用戶的線程。工作負(fù)載分階段建模,每個階段都有自己的線程池,這相當(dāng)于有效控制了工作負(fù)載。
■Master收到小的更新內(nèi)容后,弄清楚如何構(gòu)建進(jìn)入到memcache的內(nèi)容,以便最終傳送到Solr。
■消息使用一種協(xié)議緩沖器格式緩存在memcached中。
■消息發(fā)送到第二個中介,該中介將消息向外分發(fā)到邊緣,即Lucene/Solr。
■消息使用者收到中介發(fā)來的消息
■從數(shù)據(jù)庫裝入實體。
■確定更新內(nèi)容有沒有帶來任何級聯(lián)效應(yīng)。由于Solr及其他NoSQL數(shù)據(jù)庫并不進(jìn)行連接(join)操作,那樣比如樂隊名稱出現(xiàn)了變更,該變更內(nèi)容必須告知所有事件。
■實體序列化。把實體存儲在memcache中。
■將消息發(fā)送到第二個ActiveMQ中介,由它將消息傳送到邊緣,即Solr。
■中介由負(fù)責(zé)路由傳送的另一個進(jìn)程進(jìn)行偵聽。這番操作一度在Jboss中進(jìn)行,但是Jboss會不堪重負(fù),而StubHub遇到了饑餓矛盾問題,于是它把偵聽工作移到了Jboss外面。該偵聽器成了系統(tǒng)中一個實用的閥門,起到操作管理。如果StubHub需要換掉新的Solr索引,引入一種新的數(shù)據(jù)庫架構(gòu)(schema),就可以關(guān)掉這個閥門,讓消息在消息中介備份起來,再次打開閥門,消息就會再次開始流入。遇到Solr故障后恢復(fù)、復(fù)制索引和更新數(shù)據(jù)庫架構(gòu)時,閥門對StubHub的操作穩(wěn)定性起到了巨大影響。
■所有這些都是阻塞操作,所以使用線程池可以防止同時出現(xiàn)大量數(shù)據(jù)庫連接。
■Solr
■Solr提供了一項很好的文檔存儲和自然語言文本查詢功能。
■所有搜索都建立在Solr上,包括分面搜索(faceting)。
■運行速度快。查詢在10毫秒或更短時間內(nèi)返回結(jié)果。StubHub使用與SAN相連的Infiniband網(wǎng)絡(luò),發(fā)現(xiàn)自己不需要把數(shù)據(jù)緩存到內(nèi)存中,而是可以借助這個高速網(wǎng)絡(luò),以足夠快的速度從SAN提供數(shù)據(jù)。
■功能強。靈活的查詢語言、全文本搜索和地理空間搜索。
■支持許多輸出格式:XML、Atom、RSS、CSV和Json等。因而更容易與各種客戶端進(jìn)行集成。
■高頻率寫入方面不是很好。在高頻率寫入環(huán)境下,復(fù)制似乎沒有很好地集成。你看到成千上萬的變更時,進(jìn)行同步操作行不通。你得到的其實是過期數(shù)據(jù)。所以,StubHub只好擴(kuò)建了自己的復(fù)制機制。
■平面數(shù)據(jù)結(jié)構(gòu)。仍然幾乎是面向行。StubHub希望能夠支持結(jié)構(gòu)更復(fù)雜的文檔。
■DCL—雙擊瀏覽
■URL映射到編號上:性別編號、地理編號和顯示類型編號。
■類別編號和地理編號由DCL(就是XSL)使用,為LCS創(chuàng)建查詢。然后,以一般方式顯示返回的數(shù)據(jù)。所以,所有足球隊都可能有為它們創(chuàng)建的類似頁面,有著一模一樣的結(jié)構(gòu),使用URL映射、XSL和LCS。
■大大提升生產(chǎn)力,而且添加新的功能特性變得容易多了。頁面中的每個塊都是通過內(nèi)容管理系統(tǒng)(CMS)來管理的一種資產(chǎn)。它們是大段的XSL,對照從LCS檢索的上下文文檔來進(jìn)行顯示。
■有了RenderChunkByName調(diào)用,很容易在Facebook等其他服務(wù)網(wǎng)站上顯示文體活動。
■這一切都在后端進(jìn)行,旨在實現(xiàn)搜索引擎優(yōu)化(SEO)。由于搜索引擎可以檢索Ajax,StubHub不需要進(jìn)行這番操作。
■對gif文件和樣式表等進(jìn)行邊緣緩存(edge caching),但是數(shù)據(jù)緩存在服務(wù)器上。
■減少每筆交易的客戶交互次數(shù):
■客戶交互對StubHub的經(jīng)營收入來說是最大的開銷。萬一出現(xiàn)什么問題,買賣雙方就要花大量的精力來解決問題。
■增加客戶自助服務(wù)??蛻簦ㄙI賣雙方)想知道何時拿到錢和票。MyAccount屏幕讓客戶不用借助客戶服務(wù),就可以查看訂單進(jìn)度。
■把API展示在賣方面前,那樣他們就能把這些功能特性集成到自己的系統(tǒng)中。
■IVR—集成語音識別(IVR)系統(tǒng)支持客戶為查詢賬戶狀態(tài)而打來的電話。
■現(xiàn)金流量對商家來說很重要,所以StubHub致力于更快地完成支付。
■與美國職業(yè)棒球大聯(lián)盟進(jìn)行電子集成,那樣StubHub就能在賣方實際拿到門票之前,將門票直接從賣方交給買方。優(yōu)點包括:立即送票、客戶滿意度大幅提高、消除了故障點。
■生命周期總線
■用來防止在應(yīng)用程序中硬連線復(fù)雜的工作流程。結(jié)賬應(yīng)用程序不想非得為下游的所有不同業(yè)務(wù)流程而操心。你想操心的只是經(jīng)驗驗證的信用卡和訂單,不是像訂單履行和電子郵件這些東西。
■在處理遺留問題和管理網(wǎng)站出現(xiàn)的變更時很有用。
■存在所有主要生命周期事件的主題。軟件代理偵聽甲骨文的隊列,了解主題。訂單下達(dá)后,它進(jìn)入到未經(jīng)核實的狀態(tài)。偵聽器偵聽到“未經(jīng)核實的”主題后,發(fā)電子郵件給賣方,訪問網(wǎng)站、核實訂單。當(dāng)賣方核實訂單后,代理就會從買方的第三方托管賬戶收到款項,然后發(fā)郵件給買方,表示賣方已核實、何處拿票。門票確認(rèn)無誤后,款項付給賣方。
■所有這些邏輯與網(wǎng)站面向最終用戶的部分脫離開來。這些都是后臺引擎。
■TeamWorks為這些流程建模,查找薄弱環(huán)節(jié),監(jiān)控流程,核實服務(wù)級別協(xié)議 (SLA),以及觸發(fā)操作。并幫助更好地優(yōu)化后端業(yè)務(wù)流程。盡管StubHub每年的增長率達(dá)到20%,但是它不想操作團(tuán)隊的規(guī)模每年同比壯大20%。
■聯(lián)邦快遞是原始的訂單履行模式。后來添加了電子訂單履行。業(yè)務(wù)流程如下:未經(jīng)核實->自動核實;經(jīng)過核實->條形碼重新發(fā)和分發(fā)PDF文檔;訂單履行。你只要編寫遵循同一訂單生命周期的軟件代理,即可實施新的履行模式。這個邏輯并不在應(yīng)用程序中,而是在代理中,它是可以單獨部署和測試的單元。
■避免欺詐。使用與訂單履行一樣的生命周期模式,不過增加了兩個新的狀態(tài):已購買和已批準(zhǔn)。StubHub不必進(jìn)行任何變得,即可添加避免欺詐的功能。StubHub只要更改狀態(tài)機就行。軟件代理決定把它移到已批準(zhǔn)狀態(tài)或未批準(zhǔn)狀態(tài)。
■銷售點系統(tǒng)集成
■使用兩個階段的提交:在外部系統(tǒng)上預(yù)訂門票,在StubHub中把它標(biāo)為已認(rèn)購,在外部系統(tǒng)上提交購買。
■考慮擴(kuò)大這項功能的應(yīng)用范圍,那樣作為交易的一部分,其他系統(tǒng)也能購買門票。門票與旅行或酒店客房預(yù)訂捆綁起來。
■Splunk和Dye
■這是StubHub成效最顯著的項目之一。在問題調(diào)試和排除方面節(jié)省了大量時間。
■Dye—工件注入到每個請求的HTTP頭中。
■這些使用Log4j記入日志。
■使用Splunk;如果訂單有問題,你可以使用Dye標(biāo)記(Dye marker)查看日志里面的一行行內(nèi)容,往回查看屬于請求一部分的所有調(diào)用,包括對LCS等其他服務(wù)的二次調(diào)用。很容易追溯活動的根源。
■StubHub很喜歡Splunk。它就像長行的文檔存儲區(qū)。把Dye標(biāo)記和訂單編號放入到日志行,比如一系列鍵值對(key-value pair),Splunk就會讓你很容易查看日志。StubHub的儀表板用Splunk編寫而成,可顯示每分鐘交易和每分鐘交易失敗次數(shù)等統(tǒng)計數(shù)字。你可以隨意對數(shù)據(jù)進(jìn)行交叉分析。
■使用消息格式的Log4j,那樣它不會進(jìn)行動態(tài)字符串創(chuàng)建。
汲取的經(jīng)驗教訓(xùn)
■可擴(kuò)展性就是專門化。每一個問題空間(problem space)都有其獨特的特點;任何系統(tǒng)都必須是為了解決這個特定問題而構(gòu)建的。StubHub受制于對安全購票體驗的需要、票務(wù)市場具有的獨特性、突發(fā)流量和事件的變幻無常。其系統(tǒng)必須體現(xiàn)這些要求。
■一開始就使用抽象層。否則,你就只好支持遺留客戶端,早超出了你的容許范圍也得支持。
■在生產(chǎn)環(huán)境中進(jìn)行比較。實施多個解決方案,在生產(chǎn)環(huán)境中進(jìn)行一番比較,確定哪個版本效果更好。StubHub在生產(chǎn)環(huán)境中曾測試了兩種不同的數(shù)據(jù)泵版本,看看哪一個更合適。你不希望到頭來支持多套基礎(chǔ)設(shè)施。
■把工作移到Jboss外面。數(shù)量眾多的請求可能會引起Jboss處于饑餓狀態(tài),于是StubHub把工作移到了Jboss外面。
■為dye賦予因果鏈。提交請求,那樣可以跟蹤請求在整個堆棧中的情況。能夠跨整個堆棧調(diào)試問題是一大優(yōu)點。
■優(yōu)化業(yè)務(wù)流程。系統(tǒng)之間實現(xiàn)電子集成。通過在買方、賣方和職業(yè)棒球大聯(lián)盟之間充當(dāng)協(xié)調(diào)者,StubHub得以提高客戶滿意度,消除交易中大量可能存在的故障點。StubHub買下了一個流行的轉(zhuǎn)售點計劃,那樣它就能與之集成起來。
■建立在自己的API上。StubHub在花大量的時間,努力在自己的API上構(gòu)建自己的應(yīng)用程序,那樣它就能為用戶和合作伙伴更有效地管理購票體驗。
■一般化地定義資產(chǎn)。定義資產(chǎn)以便資產(chǎn)可以在任何上下文中顯示,這樣便于制作不同格式的頁面,在其他網(wǎng)站上顯示文體活動。
■從投資回報的角度,最大限度地提高開發(fā)效率。尋求提高開發(fā)人員投資回報的項目。使用Solr對StubHub來說是一大成功秘訣。它易于使用、運行速度快,又非常實用,能夠直接滿足許多類型查詢的需要。
■SEDA適用于阻塞讀取。StubHub的許多系統(tǒng)基于阻塞讀取(blocking reads),所以SEDA很適合這種使用場合。線程池防止過量占用它所要使用的資源。
■客戶端顯示。對于很酷的交互式地圖,如體育館地圖,客戶端上處理所有的用戶界面交互,可以為服務(wù)器減輕許多負(fù)擔(dān)。即使對比較大的文體活動(待售門票達(dá)1萬至2萬張)來說,下載整個列表也是比較好的解決辦法。
■選擇簡潔的框架而不是笨重的框架。笨重的框架容易使用,但也容易濫用。隱藏復(fù)雜性讓你很快對自己的網(wǎng)站失去控制,比如基于Hibernate的框架和Component的框架。驗證和業(yè)務(wù)邏輯可能會滲入到表示層。要做出謹(jǐn)慎的決定。要明白你在解決什么樣的遺留問題。
■糟糕的經(jīng)歷其實是最好的培訓(xùn)機會。說到教你如何做好事情,沒有比失敗更理想的東西了。開辦StubHub的一幫人當(dāng)初通過盡快推出功能特性來發(fā)展業(yè)務(wù),但是這留下了遺留系統(tǒng)。管理遺留系統(tǒng)的關(guān)鍵是,管理依賴關(guān)系。使用基于代理的生命周期總線式解決方案幫助StubHub了解了遺留系統(tǒng)上的依賴關(guān)系。
■使用工作流程把狀態(tài)機與應(yīng)用程序脫離開來。不要把復(fù)雜的流程嵌入到應(yīng)用程序邏輯中。把邏輯放在應(yīng)用程序的外面,那樣業(yè)務(wù)流程能夠以更靈活的方式結(jié)合起來。這使得系統(tǒng)在將來極具靈活性和適應(yīng)性。
■避免抽取、轉(zhuǎn)換和加載(ETL)。ETL帶來了你寧愿不想處理的許多依賴關(guān)系。它是個風(fēng)險因素。當(dāng)你試圖搞清楚某次變更會不會破壞你在經(jīng)濟(jì)上依賴的系統(tǒng)時,遺留數(shù)據(jù)模型其實會不斷消耗資源。
■不要疏忽了配置管理(CM)及部署。現(xiàn)在對開發(fā)人員來說,這是目前最浪費時間的方面。這讓人痛苦不堪?,F(xiàn)在就要投入到你的CM和部署系統(tǒng)。
■致力于持續(xù)改進(jìn)。持續(xù)改進(jìn)不會自然到來,需要你付出心血。對項目進(jìn)行事后分析。確保問題不會再次出現(xiàn)。貴公司在發(fā)展時,這個系統(tǒng)可能無法擴(kuò)展?,F(xiàn)在應(yīng)該做出正確的決策,否則將來要花三五倍的精力來解決問題。
■把操作閥門做入到系統(tǒng)中。比如說,如果你需要換掉一種新的數(shù)據(jù)庫架構(gòu),就要有一個閥門,那樣你就能關(guān)閉事件、再次重啟事件。
原文鏈接:
http://highscalability.com/blog/