去哪儿网机票搜索系统的高并发架构设计

上传人:工**** 文档编号:456851373 上传时间:2023-07-19 格式:DOCX 页数:8 大小:55.12KB
返回 下载 相关 举报
去哪儿网机票搜索系统的高并发架构设计_第1页
第1页 / 共8页
去哪儿网机票搜索系统的高并发架构设计_第2页
第2页 / 共8页
去哪儿网机票搜索系统的高并发架构设计_第3页
第3页 / 共8页
去哪儿网机票搜索系统的高并发架构设计_第4页
第4页 / 共8页
去哪儿网机票搜索系统的高并发架构设计_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《去哪儿网机票搜索系统的高并发架构设计》由会员分享,可在线阅读,更多相关《去哪儿网机票搜索系统的高并发架构设计(8页珍藏版)》请在金锄头文库上搜索。

1、-去哪儿网机票搜索系统的高并发架构设计Qunar成立于2005年,那时候大家还习惯打或者去代理商买机票。随着在线旅游快速开展,机票业务逐步来到线上。在“在线旅游的大浪潮下,Qunar的核心业务主要是线上机票搜索和机票销售。根据2021年9月艾瑞监测数据,在旅行类月度独立访问量统计中,去哪儿网以4474万人名列前茅。截至2021 年3月31日,去哪儿网可实时搜索约9000家旅游代理商,搜索围覆盖全球围超过28万条国及国际航线。Qunar由机票起家,核心产品包括机票搜索比价系统、机票销售OTA系统等。后来一度成为国最大旅游搜索引擎,所以最开场大家知道Qunar都是从机票开场。在Qunar,我主要工

2、作负责机票搜索系统。当时,搜索业务到达了日均十亿量级PV,月均上亿UV的规模。而整个搜索主系统设计上是比较复杂的,大概包含了七、八个子系统。那时线上效劳器压力很大,时常出现一些高并发的问题。有时候为了解决线上问题,通宵达旦连续一两周是常有的事。尽管如此,我们还是对整个搜索系统做到了高可用、可扩展。为了大家了解机票搜索的具体业务,我们从用户角度看一下搜索的过程,如以下图:根据上面的图片,简单解释下: 首页:用户按出发城市、到达城市、出发日期开场搜索机票,进入列表页。 列表页:展示第一次搜索结果,一般用户会屡次搜索,直到找到适合他的航班,然后进入详情页。 产品详情页:用户填入个人信息,开场准备下单

3、支付。从上面的介绍可以看出,过程1和2是个用户高频的入口。用户访问流量一大,必然有高并发的情况。所以在首页和列表页会做一些优化: 前端做静态文件的压缩,优化Http请求连接数,以减小带宽,让页面更快加载出来。 前后端做了数据别离,让搜索效劳解耦,在高并发情况下更灵活做负载均衡。 后端数据航班数据99%以上来自缓存,加载快,给用户更快的体验。而我们的缓存是异步刷新的机制,后面会提及到。在过亿级UV的搜索业务,其搜索结果核心指标:一是保证时间够快,二是保证结果实时最新。为了到达这个指标,搜索结果就要尽量走缓存,我们会预先把航班数据放到缓存,当航班数据变化时,增量更新缓存系统。所以,Qunar机票技

4、术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万机票的销售额。因此,搜索缓存命中率如果有微小浮动,运营、产品总监们可能两分钟就会扑到我们的工位上,和钱挂上钩的系统要慎重再慎重。这里还有几个值得关注的指标: 每台搜索实例的QPS搜索有5060台虚拟机实例,按最大并发量,每台请求吞吐量1000。 搜索结果的 Average-Time : 一般从C端用户体验来说,Average-Time 不能超过3秒的。了解完机票搜索大概的流程,下面就来看看Qunar搜索的架构。搜索系统设计架

5、构Qunar搜索架构图上面提到搜索的航班数据都是存储在缓存系统里面。最早使用Memcached,通过一致Hash建立集群,印象大概有20台左右实例。存储的粒度就是出发地和到达地全部航班数据。随着当时Redis并发读写性能稳步提高,局部系统开场逐步迁移到Redis,比方机票低价系统、推荐系统。搜索系统按架构图,主要定义成前台搜索、后台搜索两大模块,分别用2、3标示,下面我也会重点解释。前台搜索主要读取缓存,解析,合并航班数据返回给用户端。前台搜索是基于Web效劳,顶峰期时候最大启动了50台左右的Tomcat实例。搜索的URL规则是:出发城市+到达城市+出发日期,这和缓存系统存储最小单元:出发城市

6、+到达城市+出发日期是一致的。Tomcat效劳我们是通过Ngin*来做负载均衡,用Lua脚本区分是国际航线还是国航线,基于航线类型,Ngin*会跳转不同搜索效劳器:主要是国际搜索、国搜索(基于业务、数据模型、商业模式,完全分开部署)。不光如此,Lua还用来敏捷开发一些根本效劳:比方维护城市列表、机场列表等。航班数据上文我们一直提到航班数据,接下来简单介绍下航班的概念和根本类型,让大家有个印象,明白的同学可以跳过: 单程航班:也叫直达航班,比方BJ()飞NY(纽约)。 往返航班:比方BJ飞NY,然后又从NY返回BJ。 带中转:有单程中转、往返中转;往返中转可以一段直达,一段中转。也可以两段都有中

7、转,如以下图:其实,还有更复杂的情况:如果哪天在BJ的你想来一次说走就走的旅行,想要去NY(纽约)。你选择了BJ直飞NY的单程航班。后来,你觉得去趟米国老不容易,想顺便去LA玩。那你可以先BJ飞到LA,玩几天,然后LA再飞NY。不过,去了米国要回来吧,你也许:1. NY直接飞回BJ。2. 突然玩性大发,中途顺便去日本,从NY飞东京,再从东京飞BJ。3. 还没玩够.还要从NY飞夏威夷玩,然后夏威夷飞东京,再东京飞首尔,最后首尔返回。有点复杂吧,这是去程中转、回程屡次中转的航班路线。对应国际航班还算非常正常的场景,比方从中国去肯尼亚、阿根廷,因为没有直达航班,就会遇到屡次中转。所以,飞国外有时候是

8、蛮有意思、蛮麻烦的一件事。通过上面例子,大家了解到了机票中航线的复杂程度。但是,我们的缓存其实是有限的,它只保存了两个地方的航班信息。这样简单的设计也是有必然出发点:考虑用最简单的两点一线,才能最大限度上组合复杂的线路。所以在前台搜索,我们还有大量工作要做,总而言之就是:按照最终出发地、目的地,根据一定规则搜索出用户想要的航班路线。这些规则可能是:飞行时间最短、机票价格最廉价一般中转就会廉价、航班中转最少、最宜飞行时间。你看,机票里面的航线是不是变成了数据构造里面的有向图,而搜索就等于在这个有向图中,按照一定的权重求出最优路线的过程!高并发下多线程应用我们后端技术栈基于Java。为了搜索变得更

9、快,我们大量把Java多线程特性用到了并行运算上。这样,充分利用CPU资源,让计算航线变得更快。比方下面这样中转航线,就会以多线程方式并行先处理每一段航班。类似这样场景很多:Java的多线程对于高并发系统有下面的优势: Java E*ecutor框架提供了完善线程池管理机制:譬如newCachedThreadPool、 SingleThreadE*ecutor 等线程池。 FutureTask类灵活实现多线程的并行、串行计算。 在高并发场景下,提供了保证线程平安的对象、方法。比方经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程平安的Stri

10、ngBuilder取代String、StringBuffer等等Java在多线程这块实现是非常优秀和成熟的。高并发下数据传输因为每次搜索机票,返回的航班数据是很多的: 包含各种航线组合:单程、单程一次中转、单程屡次中转,往返更不用说了。 航线上又区分上百种航空公司的组合。比方到纽约,有美国航空,国航,大,东京等等各个国家的各大航空公司,琳琅满目。则,最早航班数据用标准的*ML、JSON存储,不过随着搜索量不断飙升,CPU和带宽压力很大了。后来采取自己定义一种t*t格式来传输数据:一方面数据压缩到原来30%40%,极大的节约了带宽。同时CPU的运算量大大减低,效劳器数量也随之减小。在大用户量、高

11、并发的情况下,是特别能看出开源系统的特点:比方机票的数据解析用到了很多第三方库,当时我们也用了Fastjson。在正常情况下,Fastjson 确实解析很快,一旦并发量上来,就会越来越吃存,甚至JVM很快出现存溢出。原因呢,很简单,Fastjson设计初衷是:先把整个数据装载到存,然后解析,所以执行很快,但很费存。当然,这不能说Fastjson不优秀,现在看 GitHub上有8000多star。只是它不适应刚刚的业务场景。这里顺便说到联想到一个事:互联网公司因为快速开展,需要新技术来支撑业务。则,应用新的技术应该注意些什么呢.我的体会是: 好的技术要大胆尝试,慎重使用。 优秀开源工程,注意是优

12、秀。使用前一定弄清他的使用场景,多做做压力测试。 高并发的用户系统要做A/B测试,然后逐步导流,最后上线后还要有个观察期。后台搜索后台搜索系统的核心任务是从外部的GDS系统抓取航班数据,然后异步写入缓存。首先说一个概念GDS(Global Distribution System)即“全球分销系统,是应用于民用航空运输及整个旅游业的大型计算机信息效劳系统。通过GDS,普及全球的旅游销售机构可以及时地从航空公司、旅馆、租车公司、旅游公司获取大量的与旅游相关的信息。机票的源数据都来自于各种GDS系统,但每个GDS却千差万别:1. 效劳器遍布全球各地:国GDS主要有中航信的IBE系统、黑屏数据去机场、

13、火车站看到售票员输入的电脑终端系统,国际GDS遍布于东南亚、北美、欧洲等等。2. 通讯协议不一样,HTTPAPI、Webservice、Socket等等。3. 效劳不稳定,尤其国外的GDS,受网路链路影响,访问很慢十几分钟长连接很常见,效劳白天经常性挂掉。4. 更麻烦的是:GDS一般付费按次查询,在大搜索量下,实时付费用它,估计哪家公司都得破产。而且就算有钱 , 各种历史悠久的GDS是无法承载任何的高并发查询。更苦的是,因为是创业公司,我们大都只能用免费的GDS,它们都是极其不稳定的。所谓廉价没好货,最搞笑的一次是:曾经在米国的GDS挂了一、两天,技术们想联系效劳商沟通效劳器问题。因为是免费,

14、就没有所谓的效劳商一说,最后产品总监算兼职商务吧给了一个国外的网址,翻开是这家效劳商的工单页面,全英文,没有留任何。提交工单后,不知道什么时候回复。可以想想当时我的心情.虽然有则多困难,我们还是找到一些技术方案,具体如下。引入NIO框架考虑GDS访问慢,不稳定,导致很多长连接。我们大量使用NIO技术:NIO,是为了弥补传统I/O工作模式的缺乏而研发的,NIO的工具包提出了基于Selector选择器、Buffer缓冲区、Channel通道的新模式;Selector选择器、可选择的Channel通道和SelectionKey选择键配合起来使用,可以实现并发的非阻塞型I/O能力。NIO并不是一下就凭

15、空出来的,那是因为 Epoll 在Linu*2.6核中正式引入,有了I/O多路复用技术,它可以处理更多的并发连接。这才出现了各种应用层的NIO框架。HTTP、Socket 都支持了NIO方式,在和GDS通信过程中,和过去相比: 通信从同步变成异步模式:CPU的开销、存的占用都减低了一个数量级。 长连接可以支持更长超时时间,对国外GDS通信要可靠多了。 提高了后台搜索效劳器的稳定性。消息队列为了异步完成航班数据更新到缓存,我们采用消息队列方式(主备AMQ)来管理这些异步任务。具体实现如下。有一个问题,如何判断缓存过期呢.这里面有一个复杂的系统来设置的,它叫Router。资深运营会用它设置可以细化到具体一个航段的缓存有效期:比方说NY,一般来说买机票的人不多的,航班信息缓存几天都没有问题。但如果,那可能就最多5分钟了。Router还有一个复杂工作,我叫它“去伪存真。我们长期发现真是廉价无好货,*些GDS返回航班数据不全是准确的,所以我们会把*些航线、甚至航班指定具体的GDS数据源,比方新加坡:直达航班数据来自于ABAQUS,但是中转数据,新加坡,或者台北新加坡从IBE来会精准些。因此Router路由规则设计要很灵活。通过消息队列,也其实采用异步化方式让效劳解耦,进展了很好的读写别离。GDS效

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号