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