火车订票分为两个部分:车票信息查询和订购车票
一:对于车票信息查询,可以采用类似张贴布告的方式,不等着用户去发请求查询,主动发布到一些大的门户网(比如新浪、腾讯)和相应的地方门户(比如回邯郸的找邯郸信息港)以及云计算平台等地方,尽可能实时的更新数据。用户要查询车票信息直接到张贴车票信息的地方去查询即可。12306服务器不再直接负责用户的查询请求。
二:对于订购车票功能,如果非要实时交互的话。我们引入车票统一排序系统,对于各种不同的车票统一排序,比如t56的硬座排序号为2348,d131的二等座排序号为982…………。这个排序算法其实算是一种协议。铁道部统一制定好,然后发布给公众。用户要订购车票的时候,只要输入这个排序号就能清楚地告诉系统他想要的是什么票。(可以在查询车票信息的结果中,返回各个车次的各种座位的排序号,这样可能方便些)。可以排序根本上是因为车票数据集合的内部结构是线性的。
订购车票功能的实现:
1. 事先准备。
在进入春运高峰期前,用户要完成注册和充值两件事。
注册返回给用户一个id(纯数字)。这个id的数字,对用户实现全排序。为了验证过程节省时间。
2. 系统初始化(也许是每个凌晨3点)
把所有的用户密码读取到一个内存里的大数组里,数组索引为用户id,元素值为密码。比如数组的第1983个元素为1234qweasd,表示用户id为1983的用户,其密码为1234qweasd。全国所有人都注册,几个g的内存也就足够了吧。
把所有的车票信息,按照排序号,初始化到一个大的对象数组里。这里的每个对象处理不同的车票的订票请求。比如我们还是按照上面举例的t56的硬座排序号为2348,那么第2348个对象用来处理对t56硬座的订票请求。
3.订票处理过程
用户请求信息 id 和密码 车票的排序号 日期 上车地 下车地
上车地,下车地,用数字来表示,表示在整个路途中,这个站排名第几。比如从第四个站上车,第九个站下车,那么上车地就是4,下车地就是9。
假如要订购2月1日,t56硬座,从第1个站到第5个站
请求信息如下: (继续用上面的例子,假设t56硬座排序号为2348)
Id和密码 + 2348 + 2.1+ 1 +5
服务器收到请求后,首先验证,以id为索引,读取密码数组里的密码,进行比对。不一致则返回验证错误,本次订票过程失败结束(结果1)。
验证成功的话调用对象数组的第2348个对象,进行订票处理。订票处理过程,首先看车票有无,没票返回无票信息,本次订票过程失败结束(结果2)
有票的话,系统把票先分给此用户,然后从其账户扣款,若失败,系统把票收回,返回账户金额不足(这个应尽量避免,只要大家都提前存够钱就不会出这个问题),本次订票过程失败结束(结果3)
如果扣款成功,那么本次订票成功完成。返回订单详细信息。(同时更新张贴的供查询的数据,以实现查询结果的实时性)(结果4)
从上面过程,我们看到一次订票,用户只发送一次请求,收到一次回应。通信量很少。
而且所有处理都在内存,没有读取磁盘的时间开销。而且实现我们已经建立好了秩序,对于两个大的数组,我们都是直接定位元素,没有排序和查找过程。结论就是整个过程,只有少量的通信和内存中的数据计算,有理由相信,完成一次订票过程,需要的时间应该很少。即使高并发,我们开始多服务器均衡,比如一个服务器只完成验证,然后100台服务器分担不同车票排序号的对象,很容易实现分而治之。
补充一点:单个服务器处理完一个请求之后再处理下一个,换言之,单个服务器单线程功能工作。避免线程切换等开销而且保证了逻辑简单和数据安全。
不过,对于订票,不一定要采用实时交互的方式,可以采用类似批处理的方式,先全面收集请求,然后统一分配。
实现思路:
用户的个人信息(或者类似的地方)填写自己的订票意向,即可以接受的车票排序(比如1最优先考虑的车票是哪个2,假如1没分到票,那么考虑哪个)。系统只要收集并分析每个用户的这部分信息,把车票做一个分配就得了。(可能有时候不得不采取抽奖类似的方法,这是供需矛盾,不是本系统可以解决的问题)分好之后,系统通知之类的方式告知用户结果,并包含凭证和详细信息就ok了。