Facebook支撐萬(wàn)億Post搜索背后的技術(shù)窺探
近日,F(xiàn)acebook為post搜索添加了Graph Search。我們來(lái)看幾個(gè)驚人的數(shù)字:Facebook每天約產(chǎn)生10億條post,post索引總數(shù)已上萬(wàn)億條,數(shù)據(jù)量超700TB。為這些post建立索引和構(gòu)建實(shí)時(shí)查詢(xún)系統(tǒng)在工程上存在非常大的挑戰(zhàn),那么Facebook又是如何應(yīng)對(duì)這一挑戰(zhàn)的?以下為譯文:
數(shù)據(jù)收集
Facebook的底層數(shù)據(jù)結(jié)構(gòu)是為了滿(mǎn)足快速迭代網(wǎng)絡(luò)服務(wù)的需要,這卻也成為構(gòu)建實(shí)時(shí)查詢(xún)系統(tǒng)所面臨的最大挑戰(zhàn)。增加新功能往往需要改動(dòng)這些數(shù)據(jù)結(jié)構(gòu),而Facebook一貫的作風(fēng)是變動(dòng)不要給工程師平添煩惱。然而,由于wall post、photo、check-in等功能采用不同的數(shù)據(jù)存儲(chǔ)機(jī)制,對(duì)底層數(shù)據(jù)結(jié)構(gòu)進(jìn)行改動(dòng)增加了以時(shí)間、地點(diǎn)和標(biāo)簽進(jìn)行排序的難度。當(dāng)前,排序和索引的數(shù)據(jù)約有70種,其中很多種都是基于特定post類(lèi)型的。此外,數(shù)據(jù)存儲(chǔ)在一個(gè)用于生產(chǎn)環(huán)境的MySQL數(shù)據(jù)庫(kù)中。這也就意味著,當(dāng)數(shù)據(jù)庫(kù)同時(shí)支撐生產(chǎn)傳輸及數(shù)據(jù)收集時(shí),負(fù)載將大幅度增加,因此這些過(guò)程必須被嚴(yán)格監(jiān)控。
索引建立
數(shù)據(jù)收集來(lái)后,我們將其存儲(chǔ)在HBase集群中,然后執(zhí)行Hadoop map-reduce任務(wù),高并行地為之建立索引。為原始數(shù)據(jù)建立索引后,然后便傳輸給搜索的基礎(chǔ)Unicorn。我們將數(shù)據(jù)分為兩塊——文檔數(shù)據(jù)和反向索引(inverted index)。每條post的文檔數(shù)據(jù)包含用于排序的相關(guān)信息。傳統(tǒng)意義上搜索索引有什么,反向索引就有什么。要建反向索引需要遍歷每一條post,并確定與假設(shè)中的哪種搜索過(guò)濾器相匹配。
索引更新
為了更新索引,我們使用Wormhole技術(shù)訂閱MySQL數(shù)據(jù)庫(kù)中的變更。一旦有新post,現(xiàn)有post被修改、刪除或與post有關(guān)的相關(guān)數(shù)據(jù)被編輯等情況發(fā)生時(shí),我們就會(huì)都對(duì)相關(guān)post進(jìn)行更新操作。為了減少重復(fù)代碼,我們使用與在“數(shù)據(jù)收集”部分提到的相同邏輯來(lái)進(jìn)行更新操作。不同之處在于,我們?cè)谑占瘮?shù)據(jù)時(shí)有意避開(kāi)緩存,因?yàn)槲覀兿氡M量避免請(qǐng)求沒(méi)有緩存過(guò)的數(shù)據(jù)。當(dāng)我們更新索引時(shí),我們將會(huì)命中緩存,因?yàn)槲覀兿M摂?shù)據(jù)是最近被訪(fǎng)問(wèn)過(guò),并且還在緩存中。
索引存儲(chǔ)
post索引要比Facebook維護(hù)的其他搜索索引大得多。在開(kāi)始搜索post之前,F(xiàn)acebook 所有的搜索索引都存儲(chǔ)在RAM中。對(duì)于快速查詢(xún)來(lái)說(shuō),這再好不過(guò)了。對(duì)小型的搜索索引來(lái)說(shuō)也是可行的。然而,將700多TB的數(shù)據(jù)存儲(chǔ)在RAM中所帶來(lái)系統(tǒng)開(kāi)銷(xiāo)是難以想象的,因?yàn)樗枰S護(hù)分布在多臺(tái)機(jī)器上的索引。協(xié)調(diào)存儲(chǔ)索引的多臺(tái)機(jī)器使它們有序地工作給系統(tǒng)帶來(lái)了巨大的性能損耗,Unicorn團(tuán)隊(duì)為此不得不尋找存儲(chǔ)post索引的新方法。我們最終敲定的解決方案是用固態(tài)閃存存儲(chǔ)大部分的索引,用RAM存儲(chǔ)存取最為頻繁的數(shù)據(jù)結(jié)構(gòu),性能得以維持。
結(jié)果排序
由于索引了1萬(wàn)億條post,絕大多數(shù)查詢(xún)返回的結(jié)果數(shù)量之多是任何人都讀不完的。為此,F(xiàn)acebook開(kāi)始設(shè)計(jì)對(duì)結(jié)果進(jìn)行排序。為了使對(duì)用戶(hù)有價(jià)值并與用戶(hù)相關(guān)的內(nèi)容浮到上面,主要采用了兩種主要策略:查詢(xún)重寫(xiě)和結(jié)果動(dòng)態(tài)打分。在執(zhí)行前,先重寫(xiě)查詢(xún),靈活增加子句,以確保查詢(xún)結(jié)果對(duì)用戶(hù)價(jià)值更大。為搜索結(jié)果進(jìn)行打分,包括基于一系列用于排序的特征進(jìn)行排序和選擇文檔。排序特征是從文檔中抽取出來(lái)的,目前一共抽取了100多項(xiàng)特征,結(jié)合排序模型,用于尋找最佳搜索結(jié)果。隨著用戶(hù)量的增長(zhǎng)和用戶(hù)反饋的增多,排序模型必將得到進(jìn)一步改善。
項(xiàng)目簡(jiǎn)史
像 Facebook 的很多其他產(chǎn)品一樣,post搜索功能也是誕生于一個(gè)編程馬拉松項(xiàng)目。而在過(guò)去的一年中,Graph Search 團(tuán)隊(duì)的幾十個(gè)人實(shí)現(xiàn)了post搜索的大部分功能——基礎(chǔ)架構(gòu)、排序和產(chǎn)品化。