「定制旅行」已经逐渐成为旅游行业「消费升级」的一个主流模式。php
随着用户对旅游服务的要求愈来愈高,对行程安排有个性化需求的消费者来讲,常规的跟团游和自由行产品已经很难知足他们的需求。在这样的环境下,马蜂窝电商业务平台也在不断探索在提供门票、机票、酒店等这样旅游电商「标品」以外,如何充分结合现有的供应商、旅行定制师资源优点,更好得知足用户需求,创造多样化服务。redis
2018 年 6 月,马蜂窝电商业务上线了支持多工单抢单的「定制旅行交易系统」(图 1)。不一样于以前电商标品链接人和商品的属性,定制旅行的本质是链接人和服务,将有定制旅行需求的消费者与有承接能力的供应商、旅行定制师实现更好的匹配。算法
图 1—马蜂窝定制旅行交易系统浏览器
经过定制旅行平台,用户能够根据本身的定制主体(我的/企业)、出发地、目的地、往返时间、人数、预算,提交个性化旅行需求,系统经过抢单、派单的方式将需求与有承接能力的供应商进行对接。服务器
最初,定制旅行系统采用的是将一个需求分发给一个供应商的一个定制师的解决方案。这样的作法存在几个明显的缺陷,好比:微信
人力承接问题:假设供应商的控制资源出现饱和,需求分配以后没有能力承接,形成需求资源的浪费;cookie
资源控制问题:当某个目的地进入淡季,供应商为了下降成品,控制资源能力减弱,没有办法承接需求。网络
为此,研发团队首先开发了多工单系统,在用户提交定制需求时,根据用户选择服务的定制师数量,由系统派发给多个供应商的多个定制师,而后在此基础上进行系统升级,引入了抢单功能,主要用于热门目的地有定制游需求的我的用户。并发
用户提交定制需求后,系统将会根据用户特征数据和供应商、定制师特征数据进行算法匹配,使用户和定制师之间进行双向选择。每一个定制需求最多能够支持三家供应商的定制师抢单同时为用户提供旅行方案,由用户挑选最终确认其中一个定制师的旅行方案为用户服务。抢单系统带来的几个好处是:框架
提高商家的积极性,经过竞争,提高商家的跟进速度和转化率
解放 BD 的大量工做量,取得更好的商家运营和转化的结果
提高平台总体转化率,将需求在马蜂窝平台释放给长尾商家机会,解决长尾商家没法从商品排序上获取流量的问题,从而达到培养、发掘潜力商家的效果
供应商主动选择需求单,可优先选择本身擅长有优点的需求单,提高转化率
图2-多工单系统改造
抢单系统的关键是高效的资源匹配和信息沟通。所以,抢单系统的核心设计主要有两点,一是抢单池的消息队列,如何知足并发需求;二是消息通知服务,如何及时有效地通知定制师。
抢单功能容许同一需求被多个供应商的多个定制师同时抢到。用户提交需求后,会进入统一的抢单消息队列。每一个需求最多会有三个定制师同时为用户提供服务;在同一企业内,只有一个定制师能够抢单。
在下降并发方面,主要是经过如下两点来实现:
根据供应商和定制师的业务范围,BD、运营根据定制师的服务能力对定制师进行按期考核划分等级,不一样的定制师经过商家后台或者微信公众号能够看到不一样的抢单池队列。
经过使用电商自研的消息总线服务,根据定制师服务范围异步分发,同时利用等级信息过滤抢单池队列,保障全部的相同等级的定制师在同一时刻看到相同的抢单池队列。
抢单接口调用时进行十余种业务防刷控制,抢单分配时,将死锁放置到可控最细粒度,保障并发度,抢单结束后,经过长链接自动更新抢单池,将该已抢需求从抢单池移除,避免过分打扰用户,同时减小定制师之间竞争形成的资源浪费。
定制旅行交易系统使用 Ko 框架,关于控制并发是采用文件锁仍是 Redis 锁的问题,主要是考虑:
文件锁 Ko_Tool_Lock.php 不存在 expire 自动释放锁的机制,若是得到锁未能正常释放会死锁。
Ko 的 $oRedis->bSetNX 加锁,能够设置 expire 可是问题是不支持 setNx 同时设置 ex(拆成 2 步,不是原子操做),性能测试抢单并发度较高,对于锁超时的偶发状况,系统能够回收资源进行再次分配,所以对于发起抢单请求的定制师,能够首先检查是否有超时未释放的锁,若是存在,则强制释放锁,而后再次尝试得到锁。
图3-锁的控制
据统计,定制师联系用户需求越及时,需求转化率越高,及时得到抢单消息通知相当重要。消息通知的方式主要有两种:PC 端消息弹窗,以及在移动端经过微信公众号的模板消息来实现。
为了实现有抢单池变动能够第一时间提醒定制师,让定制师不用本身刷新抢单池就能够实时看到最新的待抢需求,这里引入了长链接服务的解决方案,并进行了如下应用层优化:
定制师在查看商家后台时,会打开多个页面,系统须要在当前的活跃页面上进行通知。理论上来说,每一个窗口理论上都须要提供一个长连接的服务。但这样无疑上会形成长连接的资源浪费。使用“长链接复用”的方式能够解决这个问题:
(1)同一个浏览器多个tab页之间共用一个长链接ID(setcookie),重启浏览器新建conn id
(2)同一个浏览器,来回切换用户,一个用户只产生一次长链接ID(redis hash)
同一个浏览器多个 tab 页复用 conn id,互相广播,对于活跃窗口若是出现没有监听的消息,广播到活跃窗口上去。
图4-抢单系统消息通知与广播
网络异常是不可避免的,咱们不知道何时网络会断,致使长链接断掉,会对消息通知带来影响。采用重试机制,限定时间周期,监听网络有没有异常。在长链接断开时指定短期内自动重试,超过最多重试次数后,自动延长重试间隔,防止服务异常雪崩问题。
图5-重试机制
最初长链接请求打到服务器以后,服务器的承接方式是经过 PHP 进程。项目上线后发现了一个问题,服务器上的请求长时间挂在一个比较高的点上,能够处理的长链接需求受限。并且特色是内存比较大,但 CPU 消耗比较小。后来咱们采用了 Lua 协程的解决方案,不是把请求转到 PHP FPM 上,而是转接到 Lua 上,减小内存的消耗。
定制抢单功能的上线促进了供应商之间的良性竞争,可以适应供应商服务能力和资源控制力多样性而进行动态分配,确保用户的需求获得充分知足,另外,也在必定程度上促进了供应商内部的定制师考核制度不断完善。更重要的是,使定制游平台上的收益转化率有了超过 70% 的明显提高。
将来,定制旅行平台会不断完善系统功能,好比在抢单模型的扩展、抢单定制师评级自动反馈调节闭环建设等方面,但愿和你们交流,欢迎多提宝贵意见。您能够扫描下方二维码订阅「马蜂窝技术」更多内容。
本文做者:王伟阳,马蜂窝技术专家。
微信关注“马蜂窝技术”公众号,阅读更多技术干货。