正文
Qunar搜索架构图
上面提到搜索的航班数据都是存储在缓存系统里面。最早使用Memcached,通过一致Hash建立集群,印象大概有20台左右实例。 存储的粒度就是出发地和到达地全部航班数据。随着当时Redis并发读写性能稳步提高,部分系统开始逐步迁移到Redis,比如机票低价系统、推荐系统。
搜索系统按架构图,主要定义成前台搜索、后台搜索两大模块,分别用2、3标示,下面我也会重点解释。
主要读取缓存,解析,合并航班数据返回给用户端。
前台搜索是基于Web服务,高峰期时候最大启动了50台左右的Tomcat实例。搜索的URL规则是:出发城市+到达城市+出发日期,这和缓存系统存储最小单元:出发城市+到达城市+出发日期是一致的。
Tomcat服务我们是通过Nginx来做负载均衡,用Lua脚本区分是国际航线还是国内航线,基于航线类型,Nginx会跳转不同搜索服务器:主要是国际搜索、国内搜索(基于业务、数据模型、商业模式,完全分开部署)。不光如此,Lua还用来敏捷开发一些基本服务:比如维护城市列表、机场列表等。
上文我们一直提到航班数据,接下来简单介绍下航班的概念和基本类型,让大家有个印象,明白的同学可以跳过:
其实,还有更复杂的情况:
如果哪天在BJ(北京)的你想来一次说走就走的旅行,想要去NY(纽约)。你选择了BJ直飞NY的单程航班。后来,你觉得去趟米国老不容易,想顺便去LA玩。那你可以先BJ飞到LA,玩几天,然后LA再飞NY。
不过,去了米国要回来吧,你也许:
-
NY直接飞回BJ。
-
突然玩性大发,中途顺便去日本,从NY飞东京,再从东京飞BJ。
-
还没玩够?还要从NY飞夏威夷玩,然后夏威夷飞东京,再东京飞首尔,最后首尔返回北京。
…… 有点复杂吧,这是去程中转、回程多次中转的航班路线。
对应国际航班还算非常正常的场景,比如从中国去肯尼亚、阿根廷,因为没有直达航班,就会遇到多次中转。所以,飞国外有时候是蛮有意思、蛮麻烦的一件事。
通过上面例子,大家了解到了机票中航线的复杂程度。但是,我们的缓存其实是有限的,它只保存了两个地方的航班信息。这样简单的设计也是有必然出发点:考虑用最简单的两点一线,才能最大限度上组合复杂的线路。
所以在前台搜索,我们还有大量工作要做,总而言之就是:
按照最终出发地、目的地,根据一定规则搜索出用户想要的航班路线。这些规则可能是:飞行时间最短、机票价格最便宜(一般中转就会便宜)、航班中转最少、最宜飞行时间。
你看,机票里面的航线是不是变成了数据结构里面的有向图,而搜索就等于在这个有向图中,按照一定的权重求出最优路线的过程!