咱们先了解一下机票的行业背景,下图是由中航信统计的数据,蓝色的曲线表明平均每千米的票价,红色曲线指的是客运量。从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秒,怎么办?解决办法是三段超时。第四刷子是政策匹配,好不容易弄来这么多产品,不可能都直接显示给客人,须要根据运营规则进行匹配。以上,每个具体的技术可能并不复杂,但把它们综合起来,解决具体的实际问题,为公司为行业带来价值,并非件容易的事。技术的核心价值在于技术的应用,技术价值要借助技术应用和产品才能发挥出来,这比单纯的技术学习要有意思得多,但愿以上能应用到你具体的工做中。