攜程酒店搜索引擎AWS上云實踐
作者簡介:宮嫻,攜程高級后端開發(fā)工程師;Spike,攜程高級后端開發(fā)專家。
隨著攜程國際化業(yè)務的快速推進,搜索引擎作為用戶體驗中至關重要的一環(huán),上云變得志在必行。本文主要分享酒店搜索引擎遷移AWS的探索與實踐過程,內(nèi)容將涵蓋一個HTTP請求的全鏈路處理過程:包括從APP發(fā)出請求到網(wǎng)關,再到內(nèi)網(wǎng)錯綜復雜的微服務,最后到所依賴的各種持久化存儲。
一、微服務架構(gòu)帶來的挑戰(zhàn)
這次上云的是爆款業(yè)務,用戶直觀的感受是點擊TRIP APP的Hotel搜索頁的Hotel Staycation Deals。
攜程采用主流的微服務架構(gòu),看似簡單的一個搜索功能,通過BAT調(diào)用鏈的監(jiān)控,實則底下牽涉到上百個應用。BAT是攜程對開源CAT的改進版,下圖是爆款應用在BAT中的整個調(diào)用鏈:(如果想通過CAT整理出這個關系,是非常耗時的。因為CAT的UI只能顯示一個應用依賴的下游一級應用,需要用戶逐個手工遍歷)
原封不動地把所有依賴應用都遷移至云,無論從開發(fā)成本,還是從硬件成本考量,都不太合理。側(cè)面也反映出微服務架構(gòu)在遷移時,不得不面對的挑戰(zhàn)。雖然入口應用依賴了上百個下游應用,但是通常一個應用會包含多個API,而爆款業(yè)務經(jīng)過調(diào)研,實際只使用了一個API。所以是否可以只部署一個API來落地遷移呢?
感謝BAT能夠支持API維度的依賴查詢(CAT只支持應用維度)。調(diào)研后,爆款API實際依賴的應用數(shù)為僅為八個,曙光咋現(xiàn)。
下一步便是部署。記得幾年前在使用AWS時,使用命令行發(fā)布。當時有些顧慮權限問題,一條命令打錯,可能拉掛一個集群。同時每個云廠商都會有一套自己的發(fā)布系統(tǒng),學習成本也不可忽略。值得慶幸是攜程自己開源的發(fā)布系統(tǒng)TARS已經(jīng)與AWS、阿里等云發(fā)布打通,現(xiàn)在對于我們而言,無論是部署什么云,都使用統(tǒng)一的一套UI界面。
成功部署9個應用之后,我們遇到了新問題:
1)目前攜程GATEWAY只能按照服務的維度轉(zhuǎn)發(fā)流量,而無法基于API轉(zhuǎn)發(fā)。換言之,當流量從AWS的IDCA進入GATEWAY時,無法支持只轉(zhuǎn)發(fā)爆款API到IDC A,其余API轉(zhuǎn)發(fā)到IDC B。
2)應用本身點火時會依賴十多個Redis、MySQL以及其他服務,但是AWS IDC之間的存儲由于安全問題,是無法直接相互訪問的,最終導致應用啟動失敗。當然我們也可以請各個框架組件排期支持點火動態(tài)配置,根據(jù)當前IDC的配置,判斷哪些組件需要點火。但是這無疑會讓框架和應用本身都變得很笨重,合理性值得探討。反之如果把這些存儲依賴在每個IDC都重復部署一次,勢必會導致硬件和開發(fā)成本的浪費。
介于以上兩個問題,原先維護一個代碼倉庫,同時發(fā)布多個IDC的架構(gòu)變得不可行。那提取爆款API到一個單獨的應用是否可行?試想一下,提取后,業(yè)務核心業(yè)務代碼將會分布在多個應用、多個倉庫。是否可以每個IDC都獨立一套代碼?但這會導致日后的日常開發(fā)維護重復且易錯。
所以我們嘗試把核心業(yè)務邏輯提取到一個單獨的JAR,為各個IDC單獨創(chuàng)建一個代碼倉庫。新建的應用只是一個web service的殼,內(nèi)部訪問業(yè)務的JAR。如此一來,代碼不再重復,應用的責任也得到了抽象與分離。
但這又給開發(fā)帶來一個問題:每次開發(fā)新功能,先要在業(yè)務jar的倉庫完成編寫,然后再通過web service應用引用最新的jar進行調(diào)試。每改一次代碼,都要重新生成一個jar,上傳到中央maven倉庫,然后再升級POM引用版本下載到本地,這樣開發(fā)效率勢必低效。不過值得慶幸的是,攜程現(xiàn)有的單元測試率都強制80%以上,所以這會反向推動開發(fā)編寫出質(zhì)量更高的單元測試,同時降低和webservice進行集成測試時的開發(fā)成本。方案不完美,但也算是一個權衡。
二、云上數(shù)據(jù)的持久化
新應用抽取后,雖然避開了點火中無關Redis和MySQL的依賴,但并沒有避開爆款API本身依賴的2個Redis和1個MySQL。一種方案是直接通過在IDC之間架設專線,通常Redis響應都是幾毫秒,而網(wǎng)絡延遲都具有不穩(wěn)定的特點,極端可能要幾百毫秒,所以專線的網(wǎng)絡延遲對實時業(yè)務來說是不可接受的。退一步,即使部分業(yè)務能夠接受網(wǎng)絡延遲,整個攜程業(yè)務都以這種方法進行數(shù)據(jù)訪問,這條專線未來會變成一個瓶頸。
所以我們嘗試把爆款依賴的Redis和MySQL部署到多個AWS IDC。部署過程中,我們用攜程自研的持久化KV存儲Trocks替代了Redis,達到降低了硬件成本的目標。
應用雖然點火成功了,接下來就是數(shù)據(jù)同步的問題:是否需要同步?如何同步?單向復制?雙向復制?延遲容忍度如何?
爆款依賴2個Redis。1個Redis負責基于http請求的cache,所以不需要同步,框架代碼也無需做改變,默認訪問IDC本地機房Redis。換言之,IDC A的應用讀寫IDCA的Redis實例,IDC B的應用讀寫IDC B的Redis實例。
另外1個Redis和MySQL供搜索引擎使用。業(yè)務特點只讀不寫,實時同步大量從其他數(shù)據(jù)源的數(shù)據(jù),所以只需單向同步,并且對延遲性要求低。存儲的最終架構(gòu)如下:
Redis的單向復制分發(fā)使用的是攜程自研開源的XPipe。
MySQL的單向復制分發(fā)技術使用的是攜程自研的DRC。我們這個項目只用到了它的單向復制能力,其實它也支持雙向復制。
全部部署完成后,應用能夠正常啟動與工作了。復制分發(fā)的延遲一般都在幾百毫秒,極端會到秒級,符合預期。
三、云上文件的存儲與共享
在爆款API的核心搜索引擎中,用到了讀寫本地文件的技術。應用會在IDC內(nèi)網(wǎng)傳輸共享這些文件,而這些文件有些很大,可達10個G。那不同的機房如何共享呢?一種方案是把這些應用在各個AWS IDC都部署一次,但是遷移上去后,背后依賴的數(shù)據(jù)庫是否需要部署,甚至是數(shù)據(jù)庫后面龐大的Hadoop集群也一并重復部署一次?
基于KISS原則,我們首先嘗試讓AWS IDC A的服務通過專線直接訪問IDC B的文件。但是由于網(wǎng)絡不知名的原因,文件可以傳輸,卻始終無法成功。但是即使成功,仍然帶來很多隱患,例如:如此大的文件會瞬間把專線帶寬長期占滿,而真正有實時需求的通訊會卡頓受阻。最后我們嘗試通過AWS S3的服務在不同IDC之間共享文件,結(jié)果成功了,性能也滿足業(yè)務要求。
從方案的選擇上來看,AWS S3的使用場景是值得商討的。用云上產(chǎn)品一般都會有一個顧慮,就是太過依賴某種云的一個具體產(chǎn)品,當后期如果要換成其他云時,會有大量的遷移成本。例如AWS的S3 API就是定制化的:
甚至像攜程會同時使用多種云時,那就意味著會有多套代碼的維護成本。我們現(xiàn)在的解決方案就是公司內(nèi)部統(tǒng)一出一個JAR,兼容各種云文件存儲的API,使用時只要配置相關云的安全密文即可。
四、總結(jié)
受益于前期攜程技術平臺部門為上云做的大量基礎設施研發(fā),降低了業(yè)務部門上云的門檻。爆款業(yè)務的上云只是冰山一角,隨著越來越多業(yè)務的出海,會有更多的挑戰(zhàn)等待著我們。希望這篇文章能夠為有遷移云計劃的團隊開拓思路。
有了這次上云經(jīng)歷之后,現(xiàn)在每次在設計新架構(gòu)的時候,我們都會不假思索問自己幾個問題:這個架構(gòu)設計未來有上云的需求么?是否方便上云?是否方便跨云部署?