优快云上有很多大牛的文章,已经提到了对12306.cn的很多建议。我比较赞同的有:
1. CDN镜像
2. 减少静态资源请求(包括压缩减少带宽)
3. 将列车座位分表,分区存放
4. 负载均衡
5. 查询优化
6. ...
以上设计请自行搜索。
本文仅针对12306.cn近期推出的订票时可指定座位号的需求。
如果要指出和该需求最类似的场景,我认为是证券行业的实时交易系统。一边是卖出委托,一边是买入委托,卖出的不知道是否有人买,买入的也不知道是否有人卖,反正把订单提交上去就等着。后台有一个交易配对的处理程序,当双方委托价格、数量合适,即将双方的委托进行实时交易,并通知处理结果。
将订票需求和证券交易类比后,可以将座位号(可售未发车次)设计为卖出委托,实时提交的订单设计为买入委托。卖出委托按照车次(含日期时间)分库分表分区存放,买入委托除了按照车次(含日期时间)分库分表分区存放外,还需要按照委托时间分表存放,即每几小时生成一个新表存放。
订单系统接受客户的买入委托,分析订单信息,将订单实时插入到不同数据库的相应买入委托表等待处理。
为避免垃圾订单过多,可将已售空车次做标记,并在内存中缓存,遇到已售空车次,订单直接失败,不进入买入委托。
另外,每天对已发车次做转储,过期作废订单做定时清空处理。
交易配对以独立程序运行,可多进程分区域同时运行,且不和订单系统合并部署。交易配对系统的处理逻辑为:
1. 从数据库中取出本进程需要处理的未售完车次列表,并取第一优先处理车次(优先级可采用未处理订单数量,以及最近处理时间来计算);
3. 根据车次(含日期和时间)从买入委托表中按委托时间先后取出一批订单;
4. 循环每个订单,如果订单和本批次已处理的订单座位号不重复,则将订单信息处理为ATask,提交给订单处理线程池处理;否则订单加入到失败集合;
5. 将失败集合处理成一个BTask,提交给订单处理线程池处理;
6. 等待线程池发送有空闲处理能力信息;
7. 更新车次座位是否已全部发售完毕(该车次的全部卖出委托为预售或已付款)
8. 重复第1步;
订单处理线程池处理ATask过程为:
1. 判断该订单(买入委托)申请的座位号(卖出委托)状态是否为预售或已付款;如果已售,将买入委托更新为失败;如果未售,更新买入委托状态为待付款;更新卖出委托状态为预售;
订单处理线程池处理BTask过程为:
1. 批量更新买入委托状态为失败;
取消委托,付款等其他处理略。
优点:
交易配对程序可以部署很多很多个,甚至可以为每个车厢部署一个;
特点:
订单系统收到的所有买入委托的变更请求,都要以消息的形式通知交易配对程序,比如增加订单、取消订单、付款。