12306成就
创下全球最大实时票务交易系统世界记录,春运一个月抵欧洲一年。
最高可达百万并发,承受了这个世界上能秒杀任何系统的
QPS
。网站浏览量一天最高超1500亿次,峰值是双11的三倍。
抢票软件推荐
12306系统特点
跟淘宝天猫等相比,业务简单(卖票)。
流量极大。
动态库存。
12306难点
业务角度:
对于抢票来说:
- 瞬时抢票会导致对服务器有瞬间很大的压力,因此从业务设计上来说需要将抢票的压力给分散开,比如今天才开启抢 15 天之后的车票。
- 候补车票。
对于库存来说:
- 车票库存的设计是个难点,比如
A -> B -> C -> D
共 4 个车站。- 假如乘客买了
B -> C
的车票,那么同时会影响到A->C,A->D,B->C,B->D
,涉及了多个车站的排列组合。
库存扣减
目前 12306 最大的难点,在于库存扣减。
它跟传统的电商网站,最大的不同在于它的库存,它的库存是动态变化的,库存之间会互相影响。
比如有一个组合品的需求,A品是由B品和C品通过不同的比例混合而成,用户下单的时候传过来的是A品这个
SKU
。
- 但是库存扣减的时候是把它的组合品的单品(B和C),都去扣一遍的。
我们平时各种商品
SKU
库存的话,它是表里面的一行行记录。某个行程是:
杭州 -> 武汉 -> 成都。
杭州 -> 成都 ,武汉 -> 成都。
每卖出一张 武汉 -> 成都 的票,杭州 -> 成都 的票也会少一张。
计算耗费性能
一些长途,中间会经过十几个站点,而且有些城市是没有直达的车次的,中间只能换乘。
涉及了多个车站的排列组合,这里计算是比较耗费性能的。
行锁竞争激烈
购买一个行程会涉及多个站点的扣减库存,有可能这些多个站点的库存扣减是放在一个事务中的。
- 如果是在一个事务中,那么一次下单行为,可能要涉及到几十次库存扣减。
锁范围膨胀,事务就会被拉大,线程数可能迅速被占满,导致数据库可能成为性能瓶颈,并且接口性能也会有所下降。
热点问题
火车站不同的站之间都是一个具体库存,中间的库存扣了之后,那么远的这个站的库存也要扣减。
- 极端情况下,一些热门城市,中间一些站点可能比较火爆,那两端的人是不是永远买不到票。
性能瓶颈
12306 最大的瓶颈主要是在 IO
上面,这跟 12306 使用读扩散有关。
读扩散和写扩散常见于 订阅/聊天/群聊 系统。
读扩散
在扣减余票库存的时候,直接扣减对应车站,而在查询的时候,进行动态计算。
- 牺牲了读的性能,去提升写的性能。
写扩散
在写的时候,就动态计算每个车站应该扣除多少余票库存,在查询的时候直接查即可。
- 牺牲了写的性能,去提升读的性能。
12306 是读多写少的场景,使用写扩散比较好一些,这样可以减轻查询端的压力。
12306 使用读扩散的原因可能是对数据实时性有要求。
- 当扩散队列很长的时候,写入时间存在延时,可能导致不同行程的余票对不齐。
- 而且涉及排列组合过多,使用写扩散,数据冗余会比较严重,浪费存储成本。
优化抢票性能
将库存放在每台机器的本地,比如总共有 1W 个余票库存,共有 100 台机器,那么就在每台机器上方 100 个库存。
当用户抢票之后,就会在本地先扣减库存,如果本地库存不足,此时可以给用户返回一个友好提示。
- 让用户稍后再重试抢票,再将用户抢票的请求路由到其他有库存的机器上去。
如果本地库存足够的话,就先扣除本地库存,之后再发送一个
MQ
消息异步的生成高铁票的订单,等待用户支付。
- 如果用户十分钟内不支付的话,订单就失效,返还库存。
少卖和超卖问题
对于超卖来说,每次用户请求时,先扣除库存,再去生成订单。
- 这样当库存不足时,就不会再生成订单了,因此肯定不会出现超卖的问题。
对于少卖来说,总共有 100 台机器,每台机器有 100 个库存。
- 如果其中的几台机器宕机了,那么宕机的机器上的库存就没办法继续售卖,就会出现少卖的问题。
解决少卖问题
可以在每台机器上放一些冗余的库存,如果其他机器发生了宕机,就将宕机的机器上的库存给放到健康的机器上去。
- 就可以避免机器宕机而导致一部分库存卖不出去的问题了。
需要使用
Redis
来统一管理每台机器上的库存,也就是在分布式缓存Redis
中存储一份缓存。
- 在每台机器的本地也存储一份缓存,当扣减完机器本地的库存之后,再去发送一个远程请求扣减
Redis
上的库存。
用户发出抢票请求,在本地进行扣减库存操作。
如果本地库存不足,返回用户友好提示,可以稍后重试,如果所有机器上的库存都不足的话,可以直接返回用户已售罄的提示。
如果本地库存充足,在本地扣减库存之后,再向
Redis
中发送网络请求,进行库存扣减。扣减库存之后,再发送
MQ
消息,异步的生成订单,之后等待用户支付即可。
技术选型
Pivotal GemFire
Redis
在互联网公司中使用的是比较多的,而在银行、12306 很多实时交易的系统中,很多采用 Pivotal Gemfire
作为解决方案。
在银行以及 12306 这些系统中,它们对可靠性要求非常的高,因此会选择商用的
Pivotal Gemfire
。不仅性能强、高可用,而且
Gemfire
还会提供一系列的解决方案。