当前位置:首页 > 科技  > 软件

12306技术内幕,你知道吗?

来源: 责编: 时间:2024-05-29 08:57:54 83观看
导读对于未公开的技术部分,只能结合已公开的信息,去做大胆的猜想。本文提到的一些解决方案,并不一定是标准的实现,一些观点旨在引发大家的思考。12306的成就创下全球最大实时票务交易系统世界记录,春运一个月抵欧洲一年。最高

对于未公开的技术部分,只能结合已公开的信息,去做大胆的猜想。g4028资讯网——每日最新资讯28at.com

本文提到的一些解决方案,并不一定是标准的实现,一些观点旨在引发大家的思考。g4028资讯网——每日最新资讯28at.com

12306的成就

  • 创下全球最大实时票务交易系统世界记录,春运一个月抵欧洲一年。
  • 最高可达百万并发,承受了这个世界上能秒杀任何系统的QPS。
  • 网站浏览量一天最高超1500亿次,峰值是双11的三倍。

12306系统特点

  • 跟淘宝天猫等相比,业务简单(卖票)。
  • 流量极大。
  • 动态库存。

12306系统难点

目前 12306 最大的难点,在于库存扣减。g4028资讯网——每日最新资讯28at.com

它跟传统的电商网站,可能最大的不同在于它的库存, 它的库存是动态变化的,库存之间会互相影响。g4028资讯网——每日最新资讯28at.com

比如现在有一个组合品的需求,A品是由B品和C品通过不同的比例混合而成,用户下单的时候传过来的是A品这个 SKU,但是库存扣减的时候是把它的组合品的单品(B和C),都去扣一遍的。g4028资讯网——每日最新资讯28at.com

我们平时各种商品 sku 库存的话,它是表里面的一行行记录。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

某个行程是:杭州 -> 武汉 -> 成都。g4028资讯网——每日最新资讯28at.com

杭州 -> 成都 ,武汉 -> 成都。这两个是一个车次。那么每卖出一张 武汉 -> 成都 的票,杭州 -> 成都 的票也会少一张。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

举个极端的例子,火车上就一个座位,车次是从 A -> B -> C。g4028资讯网——每日最新资讯28at.com

如果卖出 B -> C 的车票,不去扣减 A-> C 库存的话,那么假设有两个用户分别买了  A-> C  和  B -> C 。那么当车行至站点B的时候,车上会有两个人,但是座位就一个。g4028资讯网——每日最新资讯28at.com

所以不同车次之间的库存是会互相影响的。g4028资讯网——每日最新资讯28at.com

A -> B -> C -> D 共 4 个车站,假如乘客买了 B -> C 的车票,那么同时会影响到 A->C,A->D,B->C,B->D。g4028资讯网——每日最新资讯28at.com

这里不会影响 A -> B 的行程,因为乘客买的是 B -> C 的车票,站点 B 才上车,不占用 A -> B 行程的座位,我下车你上车,不冲突。g4028资讯网——每日最新资讯28at.com

计算耗费性能g4028资讯网——每日最新资讯28at.com

一些长途,中间会经过十几个站点,而且有些城市是没有直达的车次的,中间只能换乘。涉及了多个车站的排列组合,这里计算是比较耗费性能的。g4028资讯网——每日最新资讯28at.com

行锁竞争会非常激烈g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

购买一个行程会涉及多个站点的扣减库存,有可能这些多个站点的库存扣减是放在一个事务中的,如果是在一个事务中,那么一次下单行为,可能要涉及到几十次库存扣减。g4028资讯网——每日最新资讯28at.com

锁范围膨胀,事务就会被拉大,线程数可能迅速被占满,导致数据库可能成为性能瓶颈,并且接口性能也会有所下降。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

热点问题g4028资讯网——每日最新资讯28at.com

火车站不同的站之间都是一个具体库存,中间的库存扣了之后,那么远的这个站的库存也要扣减。g4028资讯网——每日最新资讯28at.com

极端情况下,一些热门城市,中间一些站点可能比较火爆,那两端的人是不是永远买不到票。g4028资讯网——每日最新资讯28at.com

所以说像 12306 这种库存,其实涉及到非常多的一个行锁竞争,而且事务是非常大的。一列火车之间的库存其实是互相影响的,动态变化的。g4028资讯网——每日最新资讯28at.com

另外还会涉及到其他维度,比如 硬座、硬卧、软卧、无座 这种业务逻辑在里面。g4028资讯网——每日最新资讯28at.com

业务逻辑加上库存之间相互影响,就导致库存扣减逻辑异常复杂。g4028资讯网——每日最新资讯28at.com

解决思路

产品角度

  • 早期的 12306 是通过整点去抢票,整点就会产生非常高的流量峰值,对系统造成非常大的压力,后面采取了分时段售票,比如今天开抢 15 天之后的车票,将抢票的压力按照时间区间分散开,大大减低了峰值。
  • 候补车票。

在2019年5月份,12306 新增了“候补购票”功能,在“候补购票”功能没出来之前,放票时间一到,千万人同时刷新抢票,这便是春运火车票秒光的原因。g4028资讯网——每日最新资讯28at.com

候补车票堪称抢了一票第三方软件的“饭碗”。g4028资讯网——每日最新资讯28at.com

“黄牛”的秘密武器是外挂,用最快的服务器不断地刷新和监控12306,刷票速度往往是正常购票的几十倍。g4028资讯网——每日最新资讯28at.com

实际上,市面上通行的“抢票软件”,原理与“黄牛”并无本质区别。g4028资讯网——每日最新资讯28at.com

以前,合肥到上海的车票卖光了,有人退票或改签,车票会回到票池可供购买。抢票软件实时刷新监控,第一时间购买,这便是抢票软件比人快的原因。g4028资讯网——每日最新资讯28at.com

现在,有了候补车票,合肥到上海的车票卖光了,乘客可以候补登记,有人退票或改签,车票按顺序优先卖给候补登记的人,而不是回到票池公开出售。这便是抢票软件无效的原因。g4028资讯网——每日最新资讯28at.com

现在很多抢票软件反而没有“候补购票”功能抢票来得快。g4028资讯网——每日最新资讯28at.com

候补车票在整个系统上相当于是一个异步过程。先排队,后面抢没抢到票再通知你。只要异步了,就可以通过消息,或者定时任务慢慢去消费,大大降低系统的压力。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

12306 是有非常多的灰色流量的,像是一些抢票软件或者脚本。因为这里面涉及到的利益非常巨大,滋生了很多灰色流量,给12306本身带来了很多额外的压力。g4028资讯网——每日最新资讯28at.com

“候补购票”功能可以降低黄牛刷票行为,拦截部分灰色流量。g4028资讯网——每日最新资讯28at.com

  • 验证码机制。BT的验证码机制,可以过滤非常大的灰色流量。

12306 的验证码,是所有验证码中的一股绝对的“清流”。g4028资讯网——每日最新资讯28at.com

2013 年起,铁道部为了应对黄牛抢票,以及各类抢票软件和插件,升级了购票验证码系统。g4028资讯网——每日最新资讯28at.com

在12306官方网站上,从购票到付款,都需要输入验证码。从最开始的字母数字验证码,再到后来升级后的图形验证码,成为了一道“难过”的关卡。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

各类奇葩验证码出现在了 12306 上。g4028资讯网——每日最新资讯28at.com

到了2015年底,根据有关网站统计,12306上的图形验证码多达接近600种。再经过排列组合,总共有多达300000种。一次性输入准确的比例仅仅是8%,两次输入准确比例27%,三次以上输入准确的比例才勉强超过60%,如果一次性输入成功的平均用时为5秒的话,按照热门车票“秒光”的情况计算,每输错一次验证码,就意味着当次购票成功率下降80%左右。g4028资讯网——每日最新资讯28at.com

直到 2018 年,各类奇葩验证码才陆续开始“下岗”。g4028资讯网——每日最新资讯28at.com

上面的候补抢票和验证码机制,主要是为了对抗黄牛。g4028资讯网——每日最新资讯28at.com

道高一尺,魔高一丈。黄牛也在不断进步。g4028资讯网——每日最新资讯28at.com

比如我是一个搞黑灰产的人,我可以雇佣一批大学生,去做图形验证码识别。简单验证码还是机器去执行。g4028资讯网——每日最新资讯28at.com

那这样的话其实还是没办法防止,但是这样增加了灰产的成本,毕竟人工比机器成本高,从一定程度上还是能够降低灰产的流量占比。g4028资讯网——每日最新资讯28at.com

12306 之所以能够使用如此变态的验证码机制的大前提是:没有把用户体验放在首位g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

12306 比较特殊,市面上几乎不存在竞争对手,而且火车票对于逢年过节,旅行返乡的人来说,几乎可以等同于必需品。g4028资讯网——每日最新资讯28at.com

在这种情况下,12306 不必将用户体验放在首位,对于 12306 来说是可以牺牲部分用户体验来换取系统稳定性。g4028资讯网——每日最新资讯28at.com

  • 12306 是读多写少的情况,查询流量占大头。

天量的火车票查询是影响 12306 性能的重要原因之一,大概占了90%以上的访问流量。更棘手的是:峰谷的查询有天壤之别,平时工作日跟这种节假日,春运。流量相差是巨大的,时间区间是非常明显的。g4028资讯网——每日最新资讯28at.com

如果说完全用机器去堆,可能就会造成一个资源浪费。g4028资讯网——每日最新资讯28at.com

还有至关重要一点是,假如完全用机器去堆,在实际业务峰值超出了初始评估量时,服务将面临无法完全承载而瘫痪,因为大规模服务器的采购、交付、部署到应用上线所耗费时间以月计,根本无法在业务量激增时"即插即用"。g4028资讯网——每日最新资讯28at.com

几乎没有办法在成本和并发能力之间做一个好的平衡。以往的一个做法是从几个关键入口流量控制,保障系统可用性,但是会影响用户体验。g4028资讯网——每日最新资讯28at.com

淘宝/天猫大促的时候,也会增加服务器,但阿里的业务盘子大,这些新增的机器很快会被其他业务(包括阿里云)消化掉,可能还不够。但是对于 12306来说,就比较难做到这一点。g4028资讯网——每日最新资讯28at.com

在 2015 年的时候,12306 跟阿里云达成合作,通过云的弹性和“按量付费”的计量方式,来支持巨量的查询业务,把架构中比较“重”(高消耗、低周转)的部分放在云上,将75%的余票查询业务切换到了阿里云上。g4028资讯网——每日最新资讯28at.com

将余票查询模块和12306现有系统做分离,在云上独立部署一套余票查询系统。g4028资讯网——每日最新资讯28at.com

通过动态的云计算,在高峰时段动态去扩容,可以达到分钟级的扩容,这样就避免在平时浪费大量的机器。g4028资讯网——每日最新资讯28at.com

合作后,提高了网站的负载能力。2019年的春运,12306挺过了流量的高峰 297 亿次的日访问量。g4028资讯网——每日最新资讯28at.com

技术角度

历史背景:12306 是在 2010 年左右上线的,11年到12年之间,基本上一到节假日系统就崩溃。当时也是被喷的不行。12年之后在 7、8月份进行了大规模的重构,到了13年的春节,整个系统就比较稳定了,基本没有 down 机的情况发生。g4028资讯网——每日最新资讯28at.com

面对 12306 这种读多写少的场景,可能我们平时会采用 Redis 这种缓存机制,12306 具体选择的解决方案,可能跟我们常见的解决方案有一些不一样。g4028资讯网——每日最新资讯28at.com

12306 通过充分调研,并没有选择 Redis,而是选择了名叫 Pivotal GemFire 的产品。g4028资讯网——每日最新资讯28at.com

没听过 Pivotal ,学 Java 的肯定都听过 Spring。g4028资讯网——每日最新资讯28at.com

Spring 框架它归属于 Spring 团队。没错框架名和团队名是一样的,这个团队归属于 Pivotal 公司。g4028资讯网——每日最新资讯28at.com

很多银行、投行,实时交易方面的系统都采用 Pivotal GemFire 作为解决方案。g4028资讯网——每日最新资讯28at.com

GemFire 基于开源项目 Geode 进行研发的。Redis 是在 2010 年左右才发行的第一个版本,Geode 是更早的一个开源项目。g4028资讯网——每日最新资讯28at.com

GemFire 本身是 Geode 的商用版本,可以理解为收费的 Redis(Redis的作者现在就在 GemFire 打工)。就像 Oracle 和 MySQL。g4028资讯网——每日最新资讯28at.com

为什么选择 Pivotal GemFire 而不是 Redis?g4028资讯网——每日最新资讯28at.com

https://redis.io/comparisons/redis-vs-gemfire/g4028资讯网——每日最新资讯28at.com

Redis 是开源的缓存解决方案,而 GemFire 是商用的,我们在互联网项目中为什么使用 Redis 比较多呢,很大原因就是因为 Redis 是开源的,不要钱。g4028资讯网——每日最新资讯28at.com

开源对应的也就是稳定性不是那么的强,并且开源社区也不会给你提供解决方案,毕竟你是白嫖的。g4028资讯网——每日最新资讯28at.com

而在银行以及 12306 这些系统中,它们对可靠性要求非常的高,因此会选择商用的 GemFire,不仅性能强、高可用,而且 GemFire 还会提供一系列的解决方案。g4028资讯网——每日最新资讯28at.com

12306 本身不缺钱,在资金预算充足的情况下,追求系统的稳定性和交易的绝对可靠,追求的是最好的解决方案。g4028资讯网——每日最新资讯28at.com

而 GemFire 类似 Oracle 是一套完整的解决方案,不只是给你一套工具,让你私有化部署就不管了,而是需要后面持续去维护的。g4028资讯网——每日最新资讯28at.com

据说 GemFire 同时做到了分布式系统里的CAP,违背了架构的一个常识。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

当时 12306 也尝试了许多其他的解决方案,都扛不住查询的流量,而使用 GemFire 之后扛住了流量,因此就使用了 GemFire。g4028资讯网——每日最新资讯28at.com

Redis 主要用作缓存存储,而当时 (12年左右) 12306 最大的瓶颈主要是在 IO 上面。g4028资讯网——每日最新资讯28at.com

为什么 12306 最大的瓶颈会在 IO 上面呢?这跟 12306 使用读扩散有关。g4028资讯网——每日最新资讯28at.com

读扩散和写扩散常见于 订阅/聊天/群聊 系统。g4028资讯网——每日最新资讯28at.com

读扩散,一般指牺牲了读的性能,去提升写的性能。g4028资讯网——每日最新资讯28at.com

写扩散,一般指牺牲了写的性能,去提升读的性能。g4028资讯网——每日最新资讯28at.com

对应 12306 来说:g4028资讯网——每日最新资讯28at.com

  • 读扩散:扣减只需要关注列车站点之间的扣减,关注车次,查询的时候再去动态计算。

优点:扣减简单;缺点:计算余票复杂。g4028资讯网——每日最新资讯28at.com

  • 写扩散:扣减直接把各个站点之间票都扣减,关注站点。

优点:扣减复杂;缺点:查询余票简单。g4028资讯网——每日最新资讯28at.com

个人猜测 12306 使用读扩散的原因是对数据实时性有要求,当扩散队列很长的时候,写入时间存在延时,可能导致不同行程的余票对不齐。g4028资讯网——每日最新资讯28at.com

而且涉及排列组合过多,使用写扩散,数据冗余会比较严重,浪费存储成本。g4028资讯网——每日最新资讯28at.com

计算余票是一个数据密集型的运算,要关联很多的数据进行计算。一方面需要数据,一方面又要频繁的计算。计算跟数据本身是分开的(计算在CPU,数据存储在内存)。g4028资讯网——每日最新资讯28at.com

GemFire 的定位是实时存储网格g4028资讯网——每日最新资讯28at.com

一般分布式缓存,比如Redis,查询数据就算再快,还是要从缓存里取出数据,再CPU进行计算。g4028资讯网——每日最新资讯28at.com

GemFire  最大的特点是将存储和计算放在了一起,它的存储和实时计算的性能目前还没有其他中间件可以取代。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

扣减库存数据库选用的是 Sybase(收费,关系型数据库),相比查询的流量,扣减库存的流量是完全可以承载的。g4028资讯网——每日最新资讯28at.com

db-engines.com 这个网站可以对比主流数据库之间的差异g4028资讯网——每日最新资讯28at.com

扣减库存之后再同步至 GemFire,然后在 GemFire 里进行动态计算,整个 GemFire 承载的是查询的流量。引入 GemFire 之后,整个系统的查询扩散瓶颈基本上就解决了。g4028资讯网——每日最新资讯28at.com

GemFire 将很多机器内存汇总成一个大的节点,作为整体去管理,尽量保证业务运算和业务数据是在同一个节点,尽量避免多节点的网络通信。g4028资讯网——每日最新资讯28at.com

图片图片g4028资讯网——每日最新资讯28at.com

但是 GemFire 也存在不足的地方,对于扩容的支持不太友好。在 12306 中,也有过测试,需要几十个T的内存就可以将业务数据全部放到内存中来,因此直接将内存给加够,也就不需要很频繁的扩容。g4028资讯网——每日最新资讯28at.com

余票库存的表如何设计?

这里的设计思路都是猜测的,并不一定是 12306 真实的设计方案。g4028资讯网——每日最新资讯28at.com

12306 余票库存的表的设计是非常特色并且重要的g4028资讯网——每日最新资讯28at.com

首先说一下需要哪几个表来表示余票的库存信息:g4028资讯网——每日最新资讯28at.com

1、基础的车次表:表示车次的编号以及发车时间等具体的车次信息,属于比较稳定的数据。g4028资讯网——每日最新资讯28at.com

2、车的座位表:表示每个座位的具体信息,包括在几车厢、几行、几列,以及 该座位的售卖情况g4028资讯网——每日最新资讯28at.com

3、车的余票表:通过座位表可以计算出每个车位在各个车站区间还有多少余票,但是动态计算比较浪费性能,因此再添加余票表,通过定时计算余票信息放入到余票表中,提高查询的性能。g4028资讯网——每日最新资讯28at.com

(其实还应该有站点表和车厢表,不过不太重要,这里直接就省略了)g4028资讯网——每日最新资讯28at.com

这里说一下这 3 个表的对应关系:g4028资讯网——每日最新资讯28at.com

比如车次为 K123,该车上有很多的座位,每个座位对应座位表中的一条数据。g4028资讯网——每日最新资讯28at.com

而余票表指的是 K123 车次上,硬座、硬卧、软卧、无座各有多少张余票,余票表的信息可以由座位表来计算得到。g4028资讯网——每日最新资讯28at.com

接下来说一下如何通过座位表来表示用户购买的车票:g4028资讯网——每日最新资讯28at.com

12306 中的车票信息其实是比较复杂的,因为各个车站之间是有依赖关系的,比如 4 个车站 A->B->C->Dg4028资讯网——每日最新资讯28at.com

如果乘客购买 B->C 的车票的话,不仅 B->C 的库存要减一,B->D 的库存也要减一,这是排列组合的情况,可以考虑通过二进制去简化车票的表示。g4028资讯网——每日最新资讯28at.com

在座位表中,我们设置一个字段 sell varchar(50) 表示该座位的售卖情况,如果该车次有 4 个站 A->B->C->D,那么 sell 字段的长度就为 3,sell 字段的第一位表示该座位 A->B 的票是否已经被买了,第二位表示 B->C 的票是否已经被买了...g4028资讯网——每日最新资讯28at.com

如果乘客购买 B->C 的车票,则 sell 字段的值为:010。g4028资讯网——每日最新资讯28at.com

如果乘客购买 B->D 的车票,此时发现该座位在 B->C 已经被卖出去了,因此不能将该座位出售给这位乘客。g4028资讯网——每日最新资讯28at.com

如果乘客购买 C->D 的车票,则 sell 字段的值为:011 ,表示 B->C,C->D 都已经有人了。g4028资讯网——每日最新资讯28at.com

通过座位表来计算出余票,得到余票表。g4028资讯网——每日最新资讯28at.com

通过余票表提升查询性能g4028资讯网——每日最新资讯28at.com

这里余票表就相当于是数据库中的视图。g4028资讯网——每日最新资讯28at.com

如果要去查询一个车次中某一个类型的余票还有多少,还需要去对座位表进行计算,这个消耗是比较大的 ,因此通过余票表来加快对于余票的查询。g4028资讯网——每日最新资讯28at.com

可以定时去计算座位表中的数据,将每种类型的座位的余票给统计出来,比如:g4028资讯网——每日最新资讯28at.com

硬卧:xx张g4028资讯网——每日最新资讯28at.com

硬座:xx张g4028资讯网——每日最新资讯28at.com

软卧:xx张g4028资讯网——每日最新资讯28at.com

...g4028资讯网——每日最新资讯28at.com

再将余票表的信息给放入到缓存中,大大提高查询的性能。g4028资讯网——每日最新资讯28at.com

我们在使用 12306 的时候,也会发现,有时候显示的有票,但是真正去买的时候发现已经没有余票了,这就说明 12306 没有保证实时的一致性,只要保证了最终一致性即可,也就是用户真正去买的时候,保证对于余票数量的查询是准确的就可以了。g4028资讯网——每日最新资讯28at.com

个人推测 12306 使用的是缓存+动态计算结合的方式,查询的时候使用的是缓存(最终一致性),等到真正下单的时候会再去动态计算一遍(实时一致性)。这样利用缓存就能隔绝掉很大的查询的流量,并且也能保证最终下单的准确性。g4028资讯网——每日最新资讯28at.com

对于电商,如果商品销售小份额的超出库存,部分场景下可以通过补充库存进行弥补,仅要求弱一致性。而 12306 属于实时的交易型系统,库存资源的数量固定,对分布式事务要求强一致性。g4028资讯网——每日最新资讯28at.com

中间的站点如果太过火爆,导致两边的站点买不到票怎么办?g4028资讯网——每日最新资讯28at.com

比如 A->B->C->D,对于一个车次中的座位来说,如果 B->C 的乘客非常多,那么是不是就会导致 A->D 买不到票了?g4028资讯网——每日最新资讯28at.com

这个是通过运营部来进行设计,首先考虑的肯定是要盈利,远途票价比较贵,因此比较倾向于远途的旅客,营业部根据具体的实际情况以及盈利情况来定一下各个区间预留多少票,给每个车站区间都留有一些余票,那么就不会因为某一个区间非常火爆,而导致其他乘客买不到长途的票了。g4028资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-91370-0.html12306技术内幕,你知道吗?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 一篇带你学习 CSS 实现卷轴滚动效果

下一篇: 大型前端应用如何做系统融合?

标签:
  • 热门焦点
Top