第六节:12306下单逻辑剖析(背景、削峰方案、同步/搜索/下单架构、下单流程/页面)

一. 背景

1. 背景介绍 

 铁道部在线车票发售网站12306基本不存在大量图片、视频这些占带宽资源的东西,所面临的主要问题就是数据库的高并发量——用中国的人口基数来算,这是一个极为恐怖的并发量,在车票发售的高峰时间点,向12306发起的并发请求数量大得就像一场国家规模的DDOS攻击。

 中国铁路客户服务中心网站(www.12306.cn)是世界规模最大的实时交易系统之一,媲美Amazon.com,节假日尤其是春节的访问高峰,网站压力巨大。据统计,在2012年初的春运高峰期间,每天有2000万人访问该网站,日点击量最高达到14亿。

2. 高并发访问分析

 那么12306做了什么样的优化,才解决了高并发访问呢?

 12306技术部主任单杏花在接受一次记者采访的时候有说到:我们研发了分布式的内存计算的余票计算技,让余票计算变得非常高效。与此同时单杏花及其团队还研发了异步交易排队系统这种系统采用售取分离、读写分离的核心系统架构等多种技术,为12306售票系统提供技术支撑。

其实通过她的描述,我们可以得出一些处理高并发访问方式:

(1)、采用内存计算(使用缓存系统)

(2)、异步处理请求(进行流量消峰)

(3)、数据库进行读写分离操作

常见的分布式缓存系统:MongoDB , Redis,MemCache

3. 流量消峰的方案:

A. 消息队列

  要对流量进行削峰,最容易想到的解决方案就是用消息队列来缓冲瞬时流量,把同步的直接调用转换成异步的间接推送,中间通过一个队列在一端承接瞬时的流量洪峰,在另一端平滑地将消息推送出去。在这里,消息队列就像“水库”一样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。

B. 答题

 你是否还记得,最早期的秒杀只是纯粹地刷新页面和点击购买按钮,它是后来才增加了答题功能的。那么,为什么要增加答题功能呢?这主要是为了增加购买的复杂度,从而达到两个目的。

 第一个目的:是防止部分买家使用秒杀器在参加秒杀时作弊。2011年秒杀非常火的时候,秒杀器也比较猖獗,因而没有达到全民参与和营销的目的,所以系统增加了答题来限制秒杀器。增加答题后,下单的时间基本控制在2s后,秒杀器的下单比例也大大下降。答题页面如下图所示。

 

 第二个目的:其实就是延缓请求,起到对请求流量进行削峰的作用,从而让系统能够更好地支持瞬时的流量高峰。这个重要的功能就是把峰值的下单请求拉长,从以前的1s之内延长到2s~10s。

这样一来,请求峰值基于时间分片了。这个时间的分片对服务端处理并发非常重要,会大大减轻压力。而且,由于请求具有先后顺序,靠后的请求到来时自然也就没有库存了,因此根本到不了最后的下单步骤,所以真正的并发写就非常有限了。

C. 分时间段进行产品上架处理

 其实处理高并发访问还有两种常见手段:静态化、集群

静态化:

 分布式缓存是为了解决数据库服务器和Web服务器之间的瓶颈,如果一个网站流量很大这个瓶颈将会非常明显,每次数据库查询耗费的时间将不容乐观。对于更新速度不是很快的站点,可以采用静态化来避免过多的数据查询,可使用Freemaker或Velocity来实现页面静态化。

集群:

 使用多台服务器去处理并发请求

 

二. 系统架构介绍

1. 数据同步架构

 系统管理员通过后台管理系统基于一些基础数据(座位数据,列车车次数据,乘车计划数据)生成指定日期的乘车计划数据。然后我们通过logstash将生成的数据同步到ES和Redis中。

 Logstash常见的数据获取方式 拉,推。拉的方式我们当前这个系统环境中不太适合,原因是因为我们使用了MyCat进行分库分表的处理,而Logstash在进行拉取数据的时候如果数据量较大我们就需要进行分页拉取,那么此时Logstash就会生成类似这样的一条sql语句:select count(*) as  count from ....来查询满足条件总条数,但是这个count别名使用了反引号,而这个反引号在MyCat中无法使用,因此就会产生异常。

 因此本次我们在进行数据同步的时候使用的是Logstash的推模式进行数据同步,如下所示:

2. 数据搜索架构

  数据同步完毕以后,用户就可以搜索相关的乘车计划数据了。具体的搜索架构如下所示:

3. 用户下单架构

 通常订票系统要处理生成订单、减扣库存、用户支付这三个基本的阶段,我们系统要做的事情是要保证火车票订单不超卖、不少卖,每张售卖的车票都必须支付才有效,还要保证系统承受极高的并发。

 这三个阶段的先后顺序改怎么分配才更加合理呢?

方案1

 当用户并发请求到达服务端时,首先创建订单,然后扣除库存,等待用户支付。这种顺序是我们一般人首先会想到的解决方案,这种情况下也能保证订单不会超卖,因为创建订单之后就会减库存,这是一个原子操作。

存在的问题:

(1) 就是在极限并发情况下,任何一个内存操作的细节都至关影响性能,尤其像创建订单这种逻辑,一般都需要存储到磁盘数据库的,对数据库的压力是可想而知的.

(2) 是如果用户存在恶意下单的情况,只下单不支付这样库存就会变少,会少卖很多订单。

 

方案2

 如果等待用户支付了订单在减库存,第一感觉就是不会少卖。但是这是并发架构的大忌,因为在极限并发情况下,用户可能会创建很多订单,当库存减为零的时候很多用户发现抢到的订单支付不了了,这也就是所谓的"超卖", 并且这种方案也不能避免并发操作数据库磁盘IO。

方案3 【最佳方案】

 从上边两种方案的考虑,我们可以得出结论:只要创建订单,就要频繁操作数据库IO。

(1). 那么有没有一种不需要直接操作数据库IO的方案呢?

   这就是预扣库存。先扣除了库存,保证不超卖,然后异步生成用户订单,这样响应给用户的速度就会快很多;

(2). 那么怎么保证不少卖呢?用户拿到了订单,不支付怎么办?

 我们都知道现在订单都有有效期,比如说用户五分钟内不支付,订单就失效了,订单一旦失效,就会加入新的库存,这也是现在很多网上零售企业保证商品不少卖采用的方案。订单的生成是异步的,一般都会放到MQ(消费队列)中处理,订单量比较少的情况下,生成订单非常快,用户几乎不用排队。

PS: 什么情况发送给rabbtimq的是订单回退消息?

   首先这里判断库存的时候,就是预扣库存的,利用redis自减的原子性(自减n),比如 返回结果为0,表示原先是有n个库存的,此时可以发送订单消息,同步库存并且可以生成订单数据;但是如果返回结果为 负数,那么表示原先的库存不足,此时不能下单,则需要向rabbitmq中发送的是订单回退的消息,然后再进行 redis 和 es 的库存回退操作。

这种方案也就是单杏花主任所提出的异步交易排队系统。当然12306网站的还有一个改造的关键技术 建立可伸缩扩展的云应用平台

根据互联网上的新闻,中国铁道科学研究院电子计算技术研究所副所长,12306网站技术负责人朱建生说,为了应对2015年春运售票高峰,该网站采取5项措施:

 一、利用外部云计算资源分担系统查询业务,可根据高峰期业务量的增长按需及时扩充。

 二、对系统的互联网接入带宽进行扩容,并可根据流量情况快速调整,保证高峰时段旅客顺畅访问网站。

 三、防范恶意抢票,通过技术手段屏蔽抢票软件产生的恶意流量,保证网站健康运行,维护互联网售票秩序。

 四、制定了多套应急预案,以应对突发情况。

 

三. 下单流程/页面

1. 下单流程

 

 

 

2. 下单页面

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2023-09-18 09:39  Yaopengfei  阅读(149)  评论(0编辑  收藏  举报