機票垂直搜尋引擎的效能優化
一、行業背景與垂直搜尋
我們先了解一下機票的行業背景,下圖是由中航信統計的資料,藍色的曲線代表平均每公里的票價,紅色曲線指的是客運量。從2011年到2016年,無論是國內、港澳臺還是國際,整體趨勢都是機票價格便宜了,坐飛機的人也越來越多了。特別是國際機票,這五年裡機票價格下降30%,客運量增長了140%。
乘客越來越多,購買機票的渠道有哪些呢?現在主要有三個:網路平臺、代售點和航司官網。像攜程、去哪兒、飛豬、同程等,是主流的網路購票平臺;像旅行社這類代售點,是旅行團的主要購票渠道;同時大部分航空公司的官網也可以購票,而且有相對較低的價格。總體來說,網路平臺是最大的銷售渠道,佔比76%。為什麼網路平臺佔有這麼大的份額呢,主要原因是機票垂直搜尋引擎是主要的使用者流量入口,使用者一般是先比價然後再去預訂,一個好的機票搜尋引擎查詢的產品豐富、價格便宜,而且響應速度快,運價也準,這些特性在技術方面實現好並不容易。
二、主要問題與解決方案
機票查詢要快、準、低。快是指查詢快,能夠提供一個良好的使用者體驗;準是指運價準,可以保證出票的成功率;低是指票價低,能夠吸引更多的使用者。但是,如果票價要有優勢,就要有大量產品,產品資料多了查詢就慢,如果查詢要快,就必須要快取,但是資料快取了,運價就可能不準。這三者是矛盾的,類似於CAP原則,具體示意圖如下:
對於以上問題,怎麼解決呢?通用的三個技術方案有:一、用DB+Redis平衡響應速度、資料實時性和查詢成本;二、用削峰填谷的MQ來處理高併發;三、將業務服務化、模組解耦。這些只是通用的技術點,並沒有什麼難度,我們這裡重點介紹與最終結果密切相關的四個模組:靜態資料、快取策略、實時查詢、政策匹配。
- 靜態資料:能靜態處理的資料儘量靜態化,儲存到本地,可以是資料庫或快取,以方便快速地查詢,如航班資訊、運價資料和政策資料等;
- 快取策略:從中航信拿到運價資料之後,進行熱冷門資料分類,資料永不過期但持續更新,自主控制資料的更新頻率;
- 實時查詢:多渠道多供應實時獲取遠端資料,多資料來源查詢速度會變慢,遠端服務不可控,解決方案是三段超時,即前端使用者超時、中端運營超時、後端供應超時;
- 政策匹配:大量的產品資料和大量的業務規則,不可能都提供給使用者,需要通過一定的演算法進行匹配過濾、排序等。
三、靜態資料與任務打底
機票查詢的靜態資料主要有:城市、機型、航司、運價資料等,這裡重點介紹較為複雜的運價資料,運價資料的獲取雖然間隔時間較長,但資料量大且更新頻次不同。運價資料是由中航信統一提供的,有兩種途徑:黑屏查詢和IBE介面,將獲取到的資料儲存到資料庫和快取中,使用者查詢的時候直接從快取中獲取,同時也會按照一定的快取策略來更新。
最初我們設計了兩套方案來打底運價資料,兩個方案各有優劣。方案1是先預載入所有的運價資料,然後全部儲存到資料庫和快取,然後在航班查詢時通過快取策略進行相應地更新;方案2是把運價資料根據航線查詢頻率分為熱門和冷門資料,然後每天凌晨對熱門資料預載入,並在航班查詢的時候對冷門資料進行更新。可以看出,方案1能保證資料的完整性和實時性,但預載入用時太長;方案2能控制預載入用時,但熱門資料的實時性會從早到晚逐漸降低。兩個方案中都需要實時更新,在考慮資料實時性的同時,還要考慮獲取資料的費用,平衡好兩者才是一個實用的方案。
綜合對比之後,我們採用了方案1,具體實現如下圖所示:首先是通過Job對運價資料的初始化,然後以任務訊息的方式傳送給MQ,MQ裡的訊息會被後臺服務自動消費,執行訊息佇列裡的任務,把運價資料儲存到資料庫和快取。資料預載入之後,使用者在前臺查詢時,如果快取裡面沒有資料,或者查到的快取資料是過期的,系統會自動發一條任務訊息給MQ,或者人工配置指定的航線定時更新,Job也會自動傳送任務訊息給MQ,前臺和後臺的訊息被服務消費以實現資料的更新。使用者的不斷請求和後臺指定的任務,保證資料的持續更新,時間越久資料的準確性越高,使用者查詢的命中率也會越來越高。
四、快取策略與資料一致
上面說到運價資料同時儲存在資料庫和快取,為什麼有了快取還要資料庫呢?儲存到資料庫是為了方便資料的多維查詢和管理,包括對快取的進一步干預。資料庫查詢的功能強大,但速度慢,快取的效能好,但從快取裡獲取的資料,會有不準確的問題。怎麼才能做到查詢快而且資料準呢?我們的解決方法是快取永不失效、資料分類、自主控制更新頻率,以實現運價資料的又快又準。
我們根據航線查詢的頻率,將可以分成熱門資料、冷門資料和沒有資料,航班多、查詢多的是熱門資料,航班少、查詢少的是冷門資料,查詢不到就是沒有資料。在預載入或更新運價資料時,將快取設定為一個較長時間或永不過期,然後在前臺訪問時,不同資料型別採用不同的更新策略,具體如下:
- 熱門航線查詢,在快取中獲取資料,資料中有一個自己的快取時間欄位,然後根據這個時間來分別處理:
- 1小時之內更新的:新鮮度較高,可以直接用;
- 1-6小時之內更新的:預警n次,第n+1次命中時則非同步更新運價;
- 6小時之外更新的:新鮮度太低,非同步更新運價;
- 冷門航線查詢,與熱門航線一樣,只是不預載入且快取時間稍長:
- 12個小時之內更新的:新鮮度較高,可以直接用;
- 12-48個小時之內更新的:預警n次,第n+1次命中時則非同步更新運價;
- 48個小時之外更新的:新鮮度太低,非同步更新運價;
- 快取沒有資料時,直接獲取最新運價,同時更新資料庫和快取。
以上無論是預警後更新還是直接更新,都是先把快取中資料返回給使用者,同時非同步更新資料庫和快取。雖然有存在資料查詢不準確的概率,但被使用者再次查詢時就準確了。查詢到的資料即便不準確,在後繼的航班預訂時也會二次的驗艙驗價,運價資料和庫存資料會再次更新。使用者不斷地查詢,資料不斷地更新,查詢命中率就會越來越高,並且用的人越多情況會越好,會逐步趨近於n個9。
五、實時查詢與三段超時
能靜態化的資料我們要儘量靜態化,但遠端資料的實時查詢還是必不可少。實時查詢如何做到又快又好呢,特別是多資料來源、多供應商的實時查詢場景。我們的國際機票查詢就是這樣,前臺頁面點選查詢時實時呼叫供應商介面,早期我們僅呼叫一個供應介面,產品比較單一,資料不夠豐富,後面我們引入了多供應商,產品變豐富了,也有了低價,但同時帶來了很多新問題,比如供應端介面需要20~30秒,但前端客戶只能接受8秒以內,怎麼辦?提高供應資料門檻?但這不是核心競爭。還有查詢速度變慢、外部資料來源不可控、資料格式多樣等問題。
對於以上問題,我們的解決辦法是三段超時,所謂三段超時,即供應端、運營端和客戶端。前端滿足客人、中間滿足運營控制策略、後端滿足供應商,三方都要滿意,這樣才能產品更豐富、價格更低、運營策略更靈活、使用者響應更及時。三段超時的時間可以根據具體場景進行配置,具體如下:
- 供應端超時:供應端是後端,是指提供資料來源的一方,供應端存在的問題就是外部不可控。供應端處於資料來源的最底端,解決辦法是儘量加大供應端的超時時間限制。我們對請求供應介面的最大HTTP超時時間設定為45秒,這個值可以滿足絕大部分情況。
- 運營端超時:運營端是中間端,把供應商的資料拿過來之後,做包裝轉換、去重、政策匹配等業務處理。我們先統計每一個供應介面的請求時間,確認供應介面資料的質量和優先順序,比如說:A供應資料的質量相比B和C供應資料的質量要高,那麼A的請求級別可以設定得高一些。我們優先考慮拿到A供應的資料,如果A的資料在8秒就返回,而B和C的超過這個時間,那麼我們此時在前臺就只把A的資料返回給客戶。對於B和C的資料,由於在HTTP請求時我們採用非同步並設定了較大的供應端超時,所以它會在A返回之後,繼續非同步請求並將返回的資料儲存到快取中,以供使用者下次或其他使用者使用。當我們拿到了多供應商的產品資料後,這時會有一定重複的資料,需要規範化處理,將不同資料格式轉換成統一標準,然後去重並選取最優,最後根據運營策略進行政策匹配等。
- 客戶端超時:客戶端是前端,需要處理最終展示和不同終端使用者的不同需求。客戶端採用多執行緒非同步讀取,這樣不會影響主執行緒的速度,同時併發請求,提升響應速度和使用者體驗。這裡指的主執行緒請求時間,可以理解為在前臺終端裝置需要等待的時間,比如APP要求8秒鐘返回,那就設定8秒時間;如果PC端B2B白屏網頁查詢,客戶可以等待時間為25秒,那麼就是設定25秒。客戶端的超時時間要大於或等於所有的運營端超時時間,例如客戶端超時是25秒,那麼運營端執行緒A的超時可以最大為25秒,但如果執行緒A的絕大部分航線獲取時間是18秒,那麼執行緒B和C的超時最好不要超過18秒,這裡的使用者體驗要綜合考慮概率問題。
六、政策匹配與演算法優化
弄來這麼多產品,不可能都提供給客人,需要根據運營規則來匹配。機票政策就是機票產品的運營控制策略,如上圖所示,包括政策型別、客戶型別、航程型別、乘客型別、航司、航班、艙位、城市、日期、返點 、定額、Office號等多種屬性。為什麼有這麼多屬性呢?因為機票產品的運營規則很複雜,而這種規則的複雜性,直接導致在航班查詢的時候,機票政策的匹配也很複雜的。對於這種大資料、複雜業務規則的資料處理,需要有一套專門的政策匹配演算法,具體如下:
第一步是直接從資料庫查政策,在前端查詢的時候,根據查詢的條件,如出發到達城市、日期等,從資料庫中大範圍的獲取政策資料,並把這些資料放到記憶體中。第二步在記憶體中對每個產品進行政策匹配即過濾,先將每一個屬性轉化為業務規則如限制城市、排除供應商、航司指定供應商等,一個屬性一個類、採用統一的介面,然後增加到政策過濾器中。產品與政策的匹配過程,就像水流過過濾網一樣,把最優政策應用到產品上如調整價格。這個過程有些複雜,為此我們編寫了一套自己的政策過濾器PolicyFilter框架。第三步是按照政策返點高低進行排序。第四步是將最優政策返回給前臺。以下是部分核心程式碼的演示:
七、小結
機票垂直搜尋效能優化不僅僅適合於機票行業,也適合於其它垂直行業,在垂直搜尋引擎方面有一定的通用性,只要它存在:遠端資料獲取、靜態資料、快取更新、規則匹配、多資料來源等問題,都是類似解決方案。垂直搜尋主要有四把刷子。第一把刷子是靜態資料與任務打底。第二把刷子是快取與更新,保持資料的新鮮度,不僅要快,還要準。第三把刷子是實時查詢與三段超時,多供應商多資料來源,供應商要20秒,客戶只能接受3秒,怎麼辦?解決辦法是三段超時。第四刷子是政策匹配,好不容易弄來這麼多產品,不可能都直接顯示給客人,需要根據運營規則進行匹配。以上,每一個具體的技術可能並不複雜,但把它們綜合起來,解決具體的實際問題,為公司為行業帶來價值,並不是件容易的事。技術的核心價值在於技術的應用,技術價值要藉助技術應用和產品才能發揮出來,這比單純的技術學習要有意思得多,希望以上能應用到你具體的工作中。