馬蜂窩定制游搶單系統設計與功能核心
「定制旅行」已經逐漸成為旅游行業「消費升級」的一個主流模式。
隨著用戶對旅游服務的要求越來越高,對行程安排有個性化需求的消費者來說,常規的跟團游和自由行產品已經很難滿足他們的需求。在這樣的環境下,馬蜂窩電商業務平臺也在不斷探索在提供門票、機票、酒店等這樣旅游電商「標品」之外,如何充分結合現有的供應商、旅行定制師資源優勢,更好得滿足用戶需求,創造多樣化服務。
2018 年 6 月,馬蜂窩電商業務上線了支持多工單搶單的「定制旅行交易系統」(圖 1)。不同于之前電商標品連接人和商品的屬性,定制旅行的本質是連接人和服務,將有定制旅行需求的消費者與有承接能力的供應商、旅行定制師實現更好的匹配。
圖 1—馬蜂窩定制旅行交易系統
搶單模式帶來的定制旅行平臺升級
通過定制旅行平臺,用戶可以根據自己的定制主體(個人/企業)、出發地、目的地、往返時間、人數、預算,提交個性化旅行需求,系統通過搶單、派單的方式將需求與有承接能力的供應商進行對接。
最初,定制旅行系統采用的是將一個需求分發給一個供應商的一個定制師的解決方案。這樣的做法存在幾個明顯的缺陷,比如:
- 人力承接問題:假設供應商的控制資源出現飽和,需求分配之后沒有能力承接,造成需求資源的浪費;
- 資源控制問題:當某個目的地進入淡季,供應商為了降低成品,控制資源能力減弱,沒有辦法承接需求。
為此,研發團隊首先開發了多工單系統,在用戶提交定制需求時,根據用戶選擇服務的定制師數量,由系統派發給多個供應商的多個定制師,然后在此基礎上進行系統升級,引入了搶單功能,主要用于熱門目的地有定制游需求的個人用戶。
用戶提交定制需求后,系統將會根據用戶特征數據和供應商、定制師特征數據進行算法匹配,使用戶和定制師之間進行雙向選擇。每個定制需求最多可以支持三家供應商的定制師搶單同時為用戶提供旅行方案,由用戶挑選最終確認其中一個定制師的旅行方案為用戶服務。搶單系統帶來的幾個好處是:
- 提升商家的積極性,通過競爭,提升商家的跟進速度和轉化率
- 解放 BD 的大量工作量,取得更好的商家運營和轉化的結果
- 提升平臺整體轉化率,將需求在馬蜂窩平臺釋放給長尾商家機會,解決長尾商家無法從商品排序上獲取流量的問題,從而達到培養、發掘潛力商家的效果
- 供應商主動選擇需求單,可優先選擇自己擅長有優勢的需求單,提升轉化率
圖2-多工單系統改造
搶單系統的關鍵是高效的資源匹配和信息溝通。因此,搶單系統的核心設計主要有兩點,一是搶單池的消息隊列,如何滿足并發需求;二是消息通知服務,如何及時有效地通知定制師。
核心技術實現
并發控制
搶單功能允許同一需求被多個供應商的多個定制師同時搶到。用戶提交需求后,會進入統一的搶單消息隊列。每個需求最多會有三個定制師同時為用戶提供服務;在同一企業內,只有一個定制師可以搶單。
在降低并發方面,主要是通過以下兩點來實現:
1. 定制師分級,使用馬蜂窩消息總線延遲消息服務,按照等級延遲通知
根據供應商和定制師的業務范圍,BD、運營根據定制師的服務能力對定制師進行定期考核劃分等級,不同的定制師通過商家后臺或者微信公眾號可以看到不同的搶單池隊列。
通過使用電商自研的消息總線服務,根據定制師服務范圍異步分發,同時利用等級信息過濾搶單池隊列,保障所有的相同等級的定制師在同一時刻看到相同的搶單池隊列。
2. 控制并發鎖粒度及鎖釋放,防止死鎖
搶單接口調用時進行十余種業務防刷控制,搶單分配時,將死鎖放置到可控最細粒度,保障并發度,搶單結束后,通過長連接自動更新搶單池,將該已搶需求從搶單池移除,避免過度打擾用戶,同時減少定制師之間競爭造成的資源浪費。
定制旅行交易系統使用 Ko 框架,關于控制并發是采用文件鎖還是 Redis 鎖的問題,主要是考慮:
- 文件鎖 Ko_Tool_Lock.php 不存在 expire 自動釋放鎖的機制,如果獲得鎖未能正常釋放會死鎖。
- Ko 的 $oRedis->bSetNX 加鎖,可以設置 expire 但是問題是不支持 setNx 同時設置 ex(拆成 2 步,不是原子操作),性能測試搶單并發度較高,對于鎖超時的偶發情況,系統可以回收資源進行再次分配,因此對于發起搶單請求的定制師,可以首先檢查是否有超時未釋放的鎖,如果存在,則強制釋放鎖,然后再次嘗試獲得鎖。
圖3-鎖的控制
消息通知-長連接
據統計,定制師聯系用戶需求越及時,需求轉化率越高,及時獲得搶單消息通知至關重要。消息通知的方式主要有兩種:PC 端消息彈窗,以及在移動端通過微信公眾號的模板消息來實現。
為了實現有搶單池變更可以***時間提醒定制師,讓定制師不用自己刷新搶單池就可以實時看到***的待搶需求,這里引入了長連接服務的解決方案,并進行了以下應用層優化:
1. 長連接復用
定制師在查看商家后臺時,會打開多個頁面,系統需要在當前的活躍頁面上進行通知。理論上來講,每個窗口理論上都需要提供一個長鏈接的服務。但這樣無疑上會造成長鏈接的資源浪費。使用“長連接復用”的方式可以解決這個問題:
(1)同一個瀏覽器多個tab頁之間共用一個長連接ID(setcookie),重啟瀏覽器新建conn id
(2)同一個瀏覽器,來回切換用戶,一個用戶只產生一次長連接ID(redis hash)
2. 消息廣播
同一個瀏覽器多個 tab 頁復用 conn id,互相廣播,對于活躍窗口如果出現沒有監聽的消息,廣播到活躍窗口上去。
圖4-搶單系統消息通知與廣播
3. 重試機制
網絡異常是不可避免的,我們不知道什么時候網絡會斷,導致長連接斷掉,會對消息通知帶來影響。采用重試機制,限定時間周期,監聽網絡有沒有異常。在長連接斷開時指定短時間內自動重試,超過最多重試次數后,自動延長重試間隔,防止服務異常雪崩問題。
圖5-重試機制
4. Lua 協程
最初長連接請求打到服務器之后,服務器的承接方式是通過 PHP 進程。項目上線后發現了一個問題,服務器上的請求長時間掛在一個比較高的點上,可以處理的長連接需求受限。而且特點是內存比較大,但 CPU 消耗比較小。后來我們采用了 Lua 協程的解決方案,不是把請求轉到 PHP FPM 上,而是轉接到 Lua 上,減少內存的消耗。
小結與未來規劃
定制搶單功能的上線促進了供應商之間的良性競爭,能夠適應供應商服務能力和資源控制力多樣性而進行動態分配,確保用戶的需求得到充分滿足,另外,也在一定程度上促進了供應商內部的定制師考核制度不斷完善。更重要的是,使定制游平臺上的收益轉化率有了超過 70% 的明顯提升。
本文作者:王偉陽,馬蜂窩技術專家,2017 年加入馬蜂窩,現負責馬蜂窩電商度假業務開發。2010 年研究生畢業于中國農業大學,曾在甲骨文、百度工作,先后從事分布式拓撲環境任務調度與報告系統,工程效率與質量平臺與工具,評估測評系統等方向的研發工作。
【本文是51CTO專欄作者馬蜂窩技術的原創文章,作者微信公眾號馬蜂窩技術(ID:mfwtech)】