我們先了解一下機票的行業背景,下圖是由中航信統計的數據,藍色的曲線代表平均每公里的票價,紅色曲線指的是客運量。從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秒,怎么辦?解決辦法是三段超時。第四刷子是政策匹配,好不容易弄來這么多產品,不可能都直接顯示給客人,需要根據運營規則進行匹配。以上,每一個具體的技術可能並不復雜,但把它們綜合起來,解決具體的實際問題,為公司為行業帶來價值,並不是件容易的事。技術的核心價值在於技術的應用,技術價值要借助技術應用和產品才能發揮出來,這比單純的技術學習要有意思得多,希望以上能應用到你具體的工作中。