作者@恺风Wei
在今年年初,我发表了高性能设计思路,兼谈12306(2014.1.20)。有个问题只讲了一部分,就是在极度繁忙的情况下如何出票。问题的来源是有人说火车票派作为很复杂,是耶非耶?
前提条件:我们讨论的是极度繁忙的情况,例如在秒级的时间,某趟列车的火车票全部销售一空。
目标方案:针对这种情况,在设计上如何最有效率的实施解决。所谓的最有效率,以最少的代码量提供最优的解决,关键在于业务逻辑。本文不讨论设计架构,只讨论业务逻辑。
为了能在最短的时间内满足用户出票申请,也就是秒杀座位,用户订票可以分为订座位和分配作为两个步骤。
1、订座位
这个在高性能设计思路,兼谈12306已经提到了。例如列车A从广州发往北京,中间停9个站,共有500个二等座位,100个一等座位。由于用户买票的同时指定了买二等票还是一等票,这相当于两个商品:
商品1、列车A从广州发往北京,中间停9个站,500个二等座位
商品2、列车A从广州发往北京,中间停9个站,100个一等座位
两个商品分别处理便罢。我们就拿商品1来看。商品1实际可以按每站分为10个货品,如下图所示。用户购买站2到站6的票,实际上是要求同时购买货品3、4、5、6。如果当中有某个货品,例如货品4的存货量为0,则购买失败,否则成功地订到票。
将一个复杂的,不确定起点和终点的票,分割后,实现就很容易,简单的减法就可以了。
2、如果最优地分配座位
用户订到票后就分配座位。能够先订后分配在于我们的前提条件,极度繁忙的秒杀座位。先提示用户成功订票,然后在显示座位。由于用户人工操作时间和人的感知时间,所以两者之间的几秒的等待时间是可以容忍的,例如可以让用户多操作一下,例如进入预定付款确认之类的。
当所有的票都订光收,看如何最优分配作为。
2.1 我们希望同一个用户等分配到同一个位置
即用户购买的货品3、4、5、6对应的同一个位置。这很容易。假设火车是不指定座位的,而通过订票,我们确保每个站路程所有用户都有座位,那么新上车的用户就找空位坐就行了。
所以,我们从先上车的用户开始分配。先分配从广州上车的,再分配站1,然后分配站2……,每次都在当前空闲座位中分配,就可以很好解决这个问题。
2.2 我们希望结伴而行的用户能分配到相邻的位置
要完全满足可能有困难,实现的算法也会比较复杂,但是要尽可能满足就比较容易。要尽可能分配到相邻的位置,既要有相邻的空位,所以在分配座位的使用,除了按起始站的先后顺序给乘客分配座位,另一个原则是相同终点站的乘客尽可能安排在一起,如尽快能安排在同一车厢。这样每次到站,空座位就尽可能连在一起,方便分配相邻座位。