Airbnb个性化搜索服务架构
導(dǎo)語(yǔ):業(yè)務(wù)快速增長(zhǎng)給搜索帶來(lái)什么樣的挑戰(zhàn)?針對(duì)類(lèi)似場(chǎng)景如何設(shè)計(jì)通用的平臺(tái)?本文詳細(xì)講述Airbnb大型搜索服務(wù)的演進(jìn)之路。
去年,Airbnb到了需要可擴(kuò)展、分布式存儲(chǔ)系統(tǒng)的時(shí)候了。例如,搜索個(gè)性化數(shù)據(jù)超過(guò)了單機(jī)的承載能力。當(dāng)我們提升了個(gè)性化服務(wù)的縱向擴(kuò)展能力的時(shí)候,意識(shí)到其他服務(wù)也有同樣的需求,因此決定設(shè)計(jì)一個(gè)通用平臺(tái),簡(jiǎn)化其他服務(wù)需要做的事情。
除了通常的請(qǐng)求/響應(yīng)模式,其他服務(wù)有不同的需求,例如,從數(shù)據(jù)源(例如,MySQL數(shù)據(jù)庫(kù))做周期性批量同步,引入新的數(shù)據(jù)源(例如,新的搜索特性),從數(shù)據(jù)流中消費(fèi)增量更新(我們的場(chǎng)景中是Kafka),或者提供數(shù)據(jù)分析能力,并且為網(wǎng)站流量提供低延遲的數(shù)據(jù)服務(wù)。隨著公司的持續(xù)增長(zhǎng),我們有很多應(yīng)用積累了越來(lái)越多的數(shù)據(jù)。如果我們能挖掘出有用的信息并且反饋給應(yīng)用,那么這些數(shù)據(jù)可以為我們的產(chǎn)品提供巨大價(jià)值。
摘要
讓我們從個(gè)性化搜索開(kāi)始。這需要保留我們的用戶行為歷史。要求能記錄實(shí)時(shí)用戶行為,并且能立即獲得記錄,以優(yōu)化個(gè)性化搜索結(jié)果(并且改善其他產(chǎn)品)。提供其他應(yīng)用能用的數(shù)據(jù)快照(例如分析或者驗(yàn)證)。需要周期性的聚合并且截?cái)鄽v史數(shù)據(jù),批量導(dǎo)入一批特征(離線計(jì)算)到系統(tǒng)中。
這些需求貫穿公司很多應(yīng)用。因此我們決定設(shè)計(jì)一個(gè)通用存儲(chǔ)平臺(tái),以支持這些需求,并幫助其他服務(wù)負(fù)責(zé)人聚焦他們特殊的業(yè)務(wù)邏輯。我們計(jì)劃在這個(gè)系統(tǒng)中滿足下面這些需求:
為網(wǎng)站流量提供低延遲操作(毫秒級(jí)別)
實(shí)時(shí)數(shù)據(jù)流提供增量更新
便捷高效的數(shù)據(jù)批量操作
保證公司增長(zhǎng)的數(shù)據(jù)和流量可擴(kuò)展
維護(hù)成本小
注意,我們將“批量操作”定義為快照和壓縮完整存儲(chǔ)庫(kù)的操作,用新快照替換現(xiàn)有快照以進(jìn)行服務(wù),將完整的新信號(hào)合并到存儲(chǔ)庫(kù)中,用新集合替換現(xiàn)有信號(hào)數(shù)據(jù)以及完整數(shù)據(jù)集上的任何其他操作。Nebula是一個(gè)平臺(tái),我們這個(gè)存儲(chǔ)上滿足了所有的這些需求。
?
什么是Nebula?
Nebula是一個(gè)無(wú)模式版本化的數(shù)據(jù)存儲(chǔ)服務(wù),提供實(shí)時(shí)隨機(jī)數(shù)據(jù)訪問(wèn)和離線批量數(shù)據(jù)管理。它包含一個(gè)支持增量數(shù)據(jù)(最近一段時(shí)間的更新)的動(dòng)態(tài)數(shù)據(jù)存儲(chǔ)的獨(dú)立服務(wù),和一個(gè)支持批量操作的靜態(tài)數(shù)據(jù)存儲(chǔ)的快照數(shù)據(jù)存儲(chǔ)。我們選擇DynamoDB作為動(dòng)態(tài)數(shù)據(jù)存儲(chǔ)(主要原因是它有很低的讀延遲,使用AWS的維護(hù)成本低),和HFileService(Airbnb內(nèi)部使用的可擴(kuò)展的靜態(tài)存儲(chǔ),支持分區(qū)和本地硬盤(pán)到HFile格式的預(yù)處理)存儲(chǔ)靜態(tài)的快照。
?
隨機(jī)數(shù)據(jù)訪問(wèn)的抽象存儲(chǔ)
Nebula為底層物理存儲(chǔ)提供了統(tǒng)一的API。API為應(yīng)用提供了通用K-V存儲(chǔ)API,增量和靜態(tài)數(shù)據(jù)內(nèi)部合并,這樣,應(yīng)用不需要為實(shí)時(shí)數(shù)據(jù)和批量數(shù)據(jù)分別部署。所以,它能靈活的遷移到不同的物理存儲(chǔ),上層應(yīng)用不需要修改API。
Nebula使用版本化列式存儲(chǔ),類(lèi)似于BigTable和HBase。版本化列式存儲(chǔ)比起原始K-V存儲(chǔ),能讓服務(wù)負(fù)責(zé)人更便捷地定義他們的數(shù)據(jù)模型。必要的時(shí)候,版本能解決沖突和跟蹤數(shù)據(jù)變更時(shí)間。應(yīng)用每行和列能存多少個(gè)版本沒(méi)有任何限制。
Nebula支持<行,列,版本>級(jí)別的原子操作。并發(fā)寫(xiě)同樣的<行,列>會(huì)有不同的版本,這樣數(shù)據(jù)能合理的存儲(chǔ)。每列都有自己的版本,并且所有的寫(xiě)直接追加到各自的列上(通過(guò)版本存儲(chǔ))。用戶隨機(jī)訪問(wèn)需要通過(guò)給定<行,列>獲取一個(gè)或者多個(gè)版本的數(shù)據(jù)。獲取多列或者多行的多次請(qǐng)求可以合并到一個(gè)單獨(dú)的多請(qǐng)求中。
使用個(gè)性化數(shù)據(jù)的一個(gè)例子,數(shù)據(jù)模型如下:
每行表示一個(gè)用戶的數(shù)據(jù),每列表示一個(gè)用戶交互類(lèi)型(又叫用戶事件),比如前面提到的搜索,每個(gè)版本是用戶事件發(fā)生時(shí)候的時(shí)間戳。在產(chǎn)品中,我們有很多用戶事件,每個(gè)事件列積累了大量的不同時(shí)間戳的事件。
為了支持一個(gè)搜索請(qǐng)求,搜索服務(wù)查找給定用戶對(duì)應(yīng)的事件數(shù)據(jù),用這些個(gè)性化數(shù)據(jù)在排序模型中決定向用戶展示的有序列表。因?yàn)檫@是搜索請(qǐng)求路徑,所以我們有很?chē)?yán)格的延遲和可用性要求。
數(shù)據(jù)能通過(guò)增量數(shù)據(jù)流(包含個(gè)人用戶事件)以單元格為單位和離線管道批量(壓縮歷史數(shù)據(jù)或者按列引導(dǎo)/合并/替換數(shù)據(jù))的方式被更新。
?
內(nèi)置批量數(shù)據(jù)處理
Nebula使用離線管道為每個(gè)倉(cāng)庫(kù)的增量數(shù)據(jù)做快照,與前面的快照合并,然后使用新的快照提供服務(wù)。這些任務(wù)跟在線服務(wù)分開(kāi)執(zhí)行,對(duì)網(wǎng)站流量的影響非常小。
管道可以根據(jù)要求進(jìn)行高級(jí)配置。例如,每個(gè)應(yīng)用可以定義他們自己的策略,如何合并新老數(shù)據(jù)(例如,新數(shù)據(jù)覆蓋老數(shù)據(jù),使用版本聚合,丟棄老數(shù)據(jù)等等),如何壓縮歷史數(shù)據(jù)(保留N個(gè)版本,刪除某段時(shí)間之前的數(shù)據(jù)等等),如何調(diào)度管道,等等。
Nebula給用戶提供定義良好的接口,用于他們定制數(shù)據(jù)并且自動(dòng)加載到系統(tǒng)中。用戶可以將他們的數(shù)據(jù)放在公共的地方,修改一些Nebula配置,然后管道將選擇并且合并數(shù)據(jù)到系統(tǒng)中以供使用。
應(yīng)用負(fù)責(zé)人能在數(shù)據(jù)快照上,將他們的特殊需求定制的邏輯放到管道上。他們的邏輯將在最新的快照數(shù)據(jù)上執(zhí)行,所以,這是一個(gè)處理邏輯的有效方式。
在個(gè)性化搜索場(chǎng)景中,我們?cè)谙铝星闆r下使用管道:
定期生成快照,合并增量數(shù)據(jù)和靜態(tài)數(shù)據(jù)
按列進(jìn)行壓縮和過(guò)濾過(guò)期事件,保證數(shù)據(jù)大小可控
離線特征計(jì)算以創(chuàng)建新的特征,批量導(dǎo)入新特征到存儲(chǔ)中
定制驗(yàn)證用戶事件的邏輯,合理的狀態(tài)檢查
所有的個(gè)性化數(shù)據(jù)都版本化,不管什么時(shí)候發(fā)現(xiàn)數(shù)據(jù)問(wèn)題,Nebula可以回滾到以前的好快照,并在版本(時(shí)間戳)之前丟棄任何不良數(shù)據(jù)。回滾邏輯根據(jù)應(yīng)用決定,但是Nebula的批量接口讓回滾邏輯實(shí)現(xiàn)很簡(jiǎn)單。
?
架構(gòu)
這是整個(gè)系統(tǒng)的架構(gòu)(如下)和設(shè)計(jì)選型。
一個(gè)Nebula讀請(qǐng)求查詢兩個(gè)數(shù)據(jù)源。增量數(shù)據(jù)存儲(chǔ)僅僅包含最新的數(shù)據(jù),快照存儲(chǔ)包含完整的數(shù)據(jù)。兩個(gè)存儲(chǔ)都支持讀查詢,但是只有動(dòng)態(tài)存儲(chǔ)接收寫(xiě)請(qǐng)求??煺沾鎯?chǔ)的更新通過(guò)切換底層快照。數(shù)據(jù)存儲(chǔ)通過(guò)Zookeeper協(xié)作。
?
動(dòng)態(tài)數(shù)據(jù)存儲(chǔ)DynamoDB
我們選擇DynamoDB是因?yàn)榈脱舆t的要求,但是也可以根據(jù)其他要求使用其他的物理存儲(chǔ)(例如HBase)替換。作為Nebula的底層存儲(chǔ),物理存儲(chǔ)只需要支持主鍵和排序二級(jí)索引。盡管底層實(shí)現(xiàn)不同上層接口卻是一致的,對(duì)于系統(tǒng)上的任何應(yīng)用(和用戶)來(lái)說(shuō),替換物理存儲(chǔ)是透明的。
我們不準(zhǔn)備去設(shè)計(jì)另外的物理存儲(chǔ),使用DynamoDB作為底層的存儲(chǔ)能讓我們非常快速的組建一個(gè)系統(tǒng)。
數(shù)據(jù)輸入流被寫(xiě)入動(dòng)態(tài)存儲(chǔ)中;它允許隨機(jī)更新,并且支持很高的QPS。DynamoDB的讀延遲很低,所以能很好的滿足我們平均10毫秒的延遲要求。我們做了一個(gè)優(yōu)化,為了保證DynamoDB表的大小容易管理,每天將數(shù)據(jù)分區(qū)到新的表。所以,我們的每個(gè)表僅僅占據(jù)一部分DynamoDB的分區(qū)以保證有高的QPS。
?
批量數(shù)據(jù)存儲(chǔ)HFileService
Nebula根據(jù)動(dòng)態(tài)更新合并起來(lái)的實(shí)時(shí)查看的最新快照存儲(chǔ)在HFileService集群中。
HFileService以低延遲高吞吐量從本地磁盤(pán)中提供靜態(tài)的HFiles(快照格式)。而且,數(shù)據(jù)加載過(guò)程對(duì)讀請(qǐng)求幾乎沒(méi)有影響,所以離線數(shù)據(jù)合并操作不影響對(duì)數(shù)據(jù)的實(shí)時(shí)訪問(wèn)。
HFileService通過(guò)動(dòng)態(tài)分片機(jī)制對(duì)數(shù)據(jù)分區(qū),所以水平擴(kuò)展能力依賴數(shù)據(jù)的總大小。盡管是靜態(tài)數(shù)據(jù),復(fù)制策略非常簡(jiǎn)單并且能隨著流量的增長(zhǎng)去調(diào)整。
?
使用離線管道做快照、壓縮和定制邏輯
Nebula支持在線隨機(jī)數(shù)據(jù)訪問(wèn)和批量操作。批量操作不影響在線訪問(wèn)。下圖描述Nebula的離線架構(gòu):
定期從增量存儲(chǔ)導(dǎo)出批量更新數(shù)據(jù)到分布式文件系統(tǒng)(Amazon S3)。數(shù)據(jù)導(dǎo)出之后,啟動(dòng)一個(gè)離線Spark任務(wù)將批量更新和歷史數(shù)據(jù)合并。我們經(jīng)常有其他的離線產(chǎn)生數(shù)據(jù)的情況,例如機(jī)器學(xué)習(xí)特征,需要批量上傳到系統(tǒng)中。合并階段經(jīng)常有這樣的情況,新快照通過(guò)合并批量更新、歷史數(shù)據(jù)和定制離線數(shù)據(jù)進(jìn)行創(chuàng)建。我們?cè)诤喜⑦^(guò)程中添加合理的檢查,避免壞數(shù)據(jù)進(jìn)入到我們的系統(tǒng)。
最新的快照存在S3上,等待下一輪合并。它也會(huì)被保存到我們的歷史數(shù)據(jù)存儲(chǔ)中。貫穿整個(gè)導(dǎo)出-合并-加載過(guò)程,實(shí)時(shí)存儲(chǔ)一直保留這些導(dǎo)出到S3的增量數(shù)據(jù),直到新的快照生成成功并且保存到歷史數(shù)據(jù)存儲(chǔ)中才會(huì)刪除。這保證了讀請(qǐng)求總通過(guò)實(shí)時(shí)和歷史存儲(chǔ)能獲取到完整數(shù)據(jù)。
S3上的完整快照被用于其他的離線數(shù)據(jù)分析。
?
流式更新輸出
除了對(duì)快照的隨機(jī)訪問(wèn)和批量處理,Nebula還支持流式更新,以保證應(yīng)用及時(shí)感知數(shù)據(jù)的更新。通過(guò)DynamoDB的流API來(lái)支持流式更新。一個(gè)單獨(dú)的組件使用Kinesis消費(fèi)者中的流,并將其發(fā)布到特定的Kafka流中,因此任何感興趣的服務(wù)都可以訂閱它。
?
其他場(chǎng)景:搜索索引基礎(chǔ)設(shè)施
說(shuō)完了Nebula,接下來(lái)講講我們?nèi)绾问褂肗ebula重構(gòu)Airbnb的搜索索引。我們先聊一下為何要重構(gòu)。
由于Airbnb大部分使用Rails / MySQL作為前端,因此搜索索引會(huì)監(jiān)聽(tīng)(并且仍然)對(duì)數(shù)據(jù)庫(kù)表進(jìn)行更改,維護(hù)當(dāng)前搜索索引文檔的緩存,并使用新文檔更新搜索實(shí)例(如果有任何更改)。由于使用輪詢加載器加載,以及從數(shù)據(jù)一致性的數(shù)據(jù)源定期同步,因此性能不確定。新的搜索機(jī)器可以通過(guò)從緩存中緩慢流式傳輸來(lái)引導(dǎo)其索引。
下面是我們決定使用這個(gè)系統(tǒng)的原因:
端到端的低延遲操作(平均時(shí)間小于1秒)
能夠通過(guò)批量任務(wù)離線處理并且合并消費(fèi)的特征到索引中
能夠使用實(shí)時(shí)特征
離線生成索引(能夠共享索引到離線分片)
快速回滾有問(wèn)題的分片
快速擴(kuò)展新的搜索實(shí)例
審核搜索索引文檔的更新
索引數(shù)據(jù)增長(zhǎng)的時(shí)候可擴(kuò)展
Nebula系統(tǒng)上面的這些特性很完美的解決了我們所有的需求。版本化列式存儲(chǔ)意味著我們能審核搜索文檔,支持批量任務(wù)意味著我們能離線生成索引(以及合并列表特征)并且直接部署到搜索中。因?yàn)檫@些索引基于快照構(gòu)建和部署,出現(xiàn)壞的索引數(shù)據(jù)我們能快速的回滾。新生成的索引被用于新的搜索實(shí)例快速啟動(dòng)(僅僅通過(guò)下載索引)。
上圖展示了基于Nebula的搜索架構(gòu)。數(shù)據(jù)快照作為離線數(shù)據(jù)合并的一部分每天生成。索引構(gòu)建器的作業(yè)對(duì)此快照進(jìn)行操作以構(gòu)建分片索引,然后像普通的二進(jìn)制部署一樣定期部署搜索。這個(gè)系統(tǒng)使用了Nebula的特性,只需要實(shí)現(xiàn)定制邏輯關(guān)聯(lián)搜索索引。
?
展望
我們?cè)贜ebula之上構(gòu)建了很多服務(wù),包括剛剛提到的搜索索引管道,個(gè)性化基礎(chǔ)設(shè)施,Airbnb的價(jià)格服務(wù)數(shù)據(jù)倉(cāng)庫(kù)。為每個(gè)應(yīng)用提供了很多TB的數(shù)據(jù),平均延遲在10毫秒。我們想鼓勵(lì)其他的團(tuán)隊(duì)使用Nebula構(gòu)建更多的應(yīng)用。
我們也計(jì)劃把我們的系統(tǒng)跟我們的數(shù)倉(cāng)深度結(jié)合,即,存儲(chǔ)歷史快照到Hive,共享更多數(shù)據(jù)流消費(fèi)邏輯,等等。為分析功能提高數(shù)據(jù)的可用性和一致性,讓系統(tǒng)管理和操作更便捷,這樣對(duì)開(kāi)發(fā)者來(lái)說(shuō)才能更容易構(gòu)建他們的應(yīng)用。
?
鳴謝
很多人的付出才把這個(gè)系統(tǒng)做起來(lái)。我們想感謝Alex Guziel為這個(gè)項(xiàng)目所做的突出貢獻(xiàn),感謝Jun He, Liyin Tang, Jingwei Lu等人的慷慨相助,還有很多人通過(guò)搜索,應(yīng)用基礎(chǔ)設(shè)施,數(shù)據(jù)基礎(chǔ)設(shè)施,產(chǎn)品基礎(chǔ)設(shè)施和其他團(tuán)隊(duì)所有以各種方式幫助的人。
?
原文地址:
https://medium.com/airbnb-engineering/nebula-as-a-storage-platform-to-build-airbnbs-search-backends-ecc577b05f06
總結(jié)
以上是生活随笔為你收集整理的Airbnb个性化搜索服务架构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Cookie或将被替换!Chrome工程
- 下一篇: Envoy为什么能战胜Ngnix——线程