一、需求是什么?
互聯網中的許多應用都有數據實時更新的需求,比如網頁搜索如何展示幾分鐘之前的新聞結果,購物搜索中價格、庫存信息的實時更新。在大數據量的情況下,數據如何做到穩定及時的更新?本文以有道購物搜索(惠惠網)價格更新為例,介紹一下數據實時更新系統的服務器端設計方案。
1.1 痛點之一:大數據不管是網頁搜索的時效性內容展示,還是購物搜索海量商品的價格、庫存信息。都是單機較難承受的,同時,大數據對系統的可擴展性,以及運維的穩定性都提出了挑戰。網頁搜索是幾百億量級,購物搜索是幾億商品量級。
1.2 痛點之二:實時性如果只是大數據,我們可以用時間換空間,傳統的慢慢的批量更新就好。但很多實際應用,用戶需要第一時間掌握最新的消息(網頁搜索場景,分鐘級別的最新新聞),用戶可能幾分鐘之內就下單,需要了解當前最準確的價格和庫存信息(購物場景,熱門商品價格和庫存變化之后,分鐘級別的更新到前臺)。實時性不可或缺。
下面具體展示幾個使用到實時價格和庫存等信息的產品例子。如圖 1 所示,購物搜索的詳情頁中展示了多個來自價格服務器的相關信息。其中用紅色橢圓標記的商品價格即為商品的實時價格,用藍色橢圓標記的價格變化趨勢是對商品歷史價格的變動趨勢概括,用土黃色橢圓標記的庫存狀態表示該商城的此商品已經處于缺貨狀態。通過點擊“價格下降”的趨勢圖標,可以彈出圖 2 所示的該商品的價格歷史截圖。不僅購物搜索會使用到實時的價格和庫存數據,購物助手在展示比價和價格歷史的時候也使用了實時的價格數據,如圖 3 所示,藍色圈起來的是價格歷史,紅色圈起來的是其它商家的實時價格。
圖1 搜索詳情頁中價格服務提供的數據截圖
圖2 索尼HX10數碼相機的價格歷史截圖
圖3 購物助手的展示示例
通過以上產品展示,我們知道在購物搜索與比價等產品中,精準的價格與庫存信息直接影響著用戶對產品的信賴。因此,這些關鍵數據的更新速度對整個產品而言就變得至關重要。在傳統的搜索引擎系統中,數據的抓取與更新一般由后臺驅動完成,即:以固定的時間以一定的頻率和策略進行數據抓取,抓到的數據與用戶的查詢之間有一段“不可接受的”的時間間隔,而這段數據緩存時間往往導致數據過期,使得搜索的結果不夠準率。對于購物搜索而言,目前的大型電商網站的商品價格經常會變動,平均每分鐘 B2C 價格變化的商品大概在 1500 左右。后臺的批量抓取在價格更新方面往往不夠及時,為了在任意時刻都能夠為用戶提供更準確的商品價格,我們為處理商品價格開發了一個新的服務,價格服務器。
價格服務器這個數據實時更新系統的設計需要解決兩個關鍵的問題:1、大規模數據抓取與更新,滿足用戶商品檢索需求的購物商品數是幾億量級。2、價格、庫存數據的實時性。商品價格/庫存變化,希望能做到分鐘級別的更新,尤其是用戶關注瀏覽的熱門商品。這些大量數據的更新能力,主要取決于我們自身的抓取能力,同時還依賴于目標電商網站的承受能力。而且價格數據的實時性則關系到用戶對產品的信賴度,直接影響著用戶在搜索或比價結果中作出的選擇。同時,價格的實時性也關系著所有依賴于它的其它服務的實效性,因為在價格更新的同時,也會觸發全網比價和降價提醒等服務的數據更新。
二、整體架構設計價格服務器的整體架構設計包含了兩方面的特性:分布式特性和實時特性。下面分別介紹其必要性和具體實現。
2.1 分布式特性隨著電商行業的飛速發展,商品的數量也在不斷的快速增加,集中式結構的 可擴展性相對較差,因此整個系統必須使用分布式的體系,將繁雜的不同的任務分配給若干個獨立的系統并行處理,能夠極大地提高了系統的性能和可擴展性。
如圖4 所示,價格服務器的分布式體系中主要由三種服務構成:任務調度服務器、抓取服務器、結果入庫服務器,分別對應圖中的 PriceServer、PriceUpdateServer 和 PriceWriteBackServer,這三種服務采用 RPC(遠程過程調用)的方式進行相互調用。其中任務調度服務器同時提供對外數據查詢的功能。由于系統的分布式特性,這三種服務每個都可以有多個實例,可以根據系統的實際需求隨時進行擴容。其中,最先可能遇到瓶頸的就是抓取服務器,分布式的架構可以簡單快捷地通過增加機器來對系統擴容,進而增加系統的抓取能力。分布式特性同時可以提高系統的穩定性,當某一臺服務不可用時,同類別的其它服務器仍可以正常運行,減少由于服務宕機導致產品不能使用的概率。
圖4 價格服務器的層次結構
2.2 實時特性整個系統的實時特性主要體現在兩個方面:1、數據更新的實時性;2、數據變化后通過其它服務的實時性。
2.2.1 基于查詢的實時抓取在海量的商品面前,由于抓取能力有限,根本無法滿足快速地更新所有的商品的價格信息,為了保證用戶對于數據高實時性的要求,應該盡可能地優先保證熱門商品的數據更新,所以實時抓取的商品選擇是比較關鍵的。我們的系統使用購物助手的瀏覽記錄以及購物搜索的查詢記錄當作熱門商品。具體流程為:用戶瀏覽某商品,購物助手獲取該用戶所瀏覽的商品 URL 以及其它商城該商品的 URL 列表發送到任務調度服務器,任務調度服務器根據上一次抓取的價格時間等信息來進行調度,將任務分配至抓取服務器,抓取服務器解析到新的價格后發送到結果入庫服務器。結果入庫服務器完成數據的更新,并通知其它價格事件監聽程序。這就完成了整個基于查詢驅動的實時抓取的過程。這種實時抓取策略就叫做“查詢驅動抓取”(簡稱 QTC,Query Triggered Crawling)。
2.2.2 數據變化的實時通知價格服務器除了實時抓取和管理所有商品的價格之外,還需要向其它服務(如降價提醒、全網比價等)提供價格變化的更新事件。如何使得其它服務可以實時地得到商品的價格變化信息呢?我們首先介紹一下觀察者模式。
觀察者模式(也被稱為發布/訂閱模式)是軟件設計模式的一種。在此種模式中,一個目標對象管理所有相依于它的觀察者對象,并且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實作事件處理系統。
觀察者模式已經在數據變化的實時通知方面被廣泛地應用,它使得服務具有高類聚、低耦合的特點。下面來介紹兩個使用了類似觀察者模式的成熟的系統,分別是 Google的咖啡因(Google Caffeine)索引系統和 Linkedin 的 Databus 數據傳輸總線。
圖5 Google 咖啡因架構
圖 5 是 Google 的咖啡因索引架構:Percolator 是基于分布式存儲系統 BigTable 的,核心在于實現了對每個文檔的隨機訪問。Percolator 的觀察者模式(observer)可以在底層數據特定列發生更新之后,被系統調用,從而實現上層應用的及時更新。在網頁搜索領域里,傳統的索引更新方案是基于 MapReduce 和其他批處理系統定時更新的,這使得索引的更新至少需要等待一輪完整的大數據處理流程完成。即使是一輪增量數據處理,相對于實際應用需要,依然是漫長不太可接受的。
再來看另外一個架構,前不久,Linkedin 公布了一個其內布使用的 Databus 項目。如圖 6 所示,Databus 的主要原理是當任何數據庫有更新時,通過分析數據庫的更新日志,將所有的數據更新事件傳輸到 Databus 總線上,進而通過各個其它服務更新數據。數據源發生完成后,Databus 能在微秒級內將事務提交給消費者。同時,消費者使用 Databus 中的服務器端過濾功能,可以只獲取自己需要的特定數據。
圖6 Linkedin 的 Databus 數據傳輸總線概要結構
顯示易見,Databus 的設計思路與 Percolator 的觀察者模式非常相似。因此,我們在價格服務器中也使用了類似的設計,將實時更新的價格變化事件通知到一系列其它的產品服務中(如降價提醒、全網比價等)。
如圖 7 所示,在價格服務器的系統中,結果入庫服務器是所有價格數據更新的必經之地,它從數據源得到最新的價格數據,通過對比底層存儲中的舊數據,就可以直接獲取到所有的價格變化,進而更新數據庫中的價格、歷史、趨勢等信息。它利用觀察者模式,將所有的價格變化事件傳送到其它監聽服務(如降價提醒、全網比價等)。每個監聽服務會根據自身的需求過濾掉沒有用的事件,因此像降價提醒這種服務可以實時地提醒用戶某個商品的降價消息。
圖7 結果入庫服務器觸發其它服務的數據流程
同時,如圖 7 所示,結果入庫服務器還會將所有的價格更新信息以日志的形式記錄下來,后臺的非實時的分析工具通過這些日志構建價格歷史、電商價格報表等。
三、數據源如圖 8 所示,價格服務器的價格更新主要來源有三個:1、抓取服務器的實時抓取;2、合作電商主動提供的數據;3、后臺定時批量抓取和解析的流程。
圖8 商品價格數據來源
這三種數據更新來源,最能保證數據實效性的是抓取服務器的實時抓取,前文已經描述它的工作原理。雖然實時抓取可以最大程度地滿足用戶查詢結果的實效性,但是覆蓋率相對較低,因此還需要其它數據源的配合才能提高商品價格更新的覆蓋率。和絕大多數搜索引擎相同,購物搜索的后臺也會定時批量地抓取大量的商品數據。同時,我們與一些商家進行了合作,這些商家會定時主動向我們的系統推送他們最新的商品數據,這些數據也包括價格和庫存等信息。有了后臺定時批量抓取流程和合作商家的推送數據,幾乎就使得絕大多數商品的數據可以得到及時地更新了。
除此之外,還會利用其它服務的日志離線觸發價格服務器更新用戶感興趣的商品的價格數據。例如:利用用戶訂閱的降價提醒商品列表定期更新這些用戶感興趣的商品的價格。又如:全網比價展示了所有最新降價的商品,這些商品的價格是否又回升了對全網比價的質量影響很大,因此,全網比價的商品列表也需要經常被更新,以防止過時的降價信息影響用戶體驗度。
總結一下,數據來源的使用主要有三點。第一、盡可能地利用多種數據來源,使價格能夠被更快速及時地更新;第二、首先保證熱門商品的價格被及時更新,熱門商品的列表來自于用戶的瀏覽記錄與搜索歷史等;第三、不能忽略非熱門的商品,非熱門商品雖然被用戶訪問的次數少,但也需要定期地被更新,只是更新間隔略長一些。
四、總結本文主要以購物搜索價格服務器,輔以 Google 咖啡因,Linkedin 的 Databus 為例,介紹了大數據實時更新框架的設計思想。框架的共同點是:1、觀察者模式,2、細粒度的更新數據到應用層。對比過去 MapReduce 的批量更新機制,更好的解決了大數據和實時性這兩大痛點。