读了几篇有关12306架构设计的博客,在这里做下简单的总结:

主要角色:用户
主要功能:查询剩余票数 售票

一 分析业务
业务复杂点:
1 库存集中:所有登录的用户访问的都是数据中心的票据数据
2 复杂的业务逻辑:还有很多查询操作,查时间,查座位,查铺位,一个车次不 行,又查另一个车次,其伴随着大量的查询操作,下单的时候需要对数据库操作。另外,关于秒杀,完全可以做成只接受前N个用户的请求(完全不操作后端的任何数据, 仅仅只是对用户的下单操作log),这种业务,只要把各个服务器的时间精确同步了就可以了,无需在当时操作任何数据库。可以订单数够后,停止秒杀,然后批量写数据库。火车票这个岂止是秒杀那么简单。能不能买到票得当时告诉用户啊。
3 数据一致性造成效率瓶颈:订票系统应该和电子商务的订单系统很相似,都是需要对库存进行:1)占住库存,2)支付(可选),3)扣除库存的操作。这个是需要有一致性的检查的,也就是在并发时需要对数据加锁的。B2C的电商基本上都会把这个事干成异步的,也就是说,你下的订单并不是马上处理的,而是延时处理的,只有成功处理了,系统才会给你一封确认邮件说是订单成功。我相信有很多朋友都收到认单不成功的邮件。这就是说,数据一致性在并发下是一个瓶颈。
4 用户量巨大:春运期间,当票放出来的时候,就会有几百万人甚至上千万人杀上去,查询,下单。几十分钟内,一个网站能接受几千万的访问量,这个是很恐怖的事情。据说12306的高峰访问是10亿PV,集中在早8点到10点,每秒PV在高峰时上千万。
5 动态库存

与淘宝对比:
淘宝要比B2C的网站要简单得多,因为没有仓库,所以,不存在像B2C这样有N个仓库对同一商品库存更新和查询的操作。下单的时候,B2C的 网站要去找一个仓库,又要离用户近,又要有库存,这需要很多计算。试想,你在北京买了一本书,北京的仓库没货了,就要从周边的仓库调,那就要去看看沈阳或 是西安的仓库有没有货,如果没有,又得看看江苏的仓库,等等。淘宝的就没有那么多事了,每个商户有自己的库存,库存分到商户头上了,反而有利于性能。

优化方案:
1 服务端处理请求的负载均衡
通过DNS的负载均衡器(一般在路由器上根据路由的负载重定向)可以把用户的访问均匀地分散在多个Web服务器上。这样可以减少Web服务器的请求负载。因为http的请求都是短作业,所以,可以通过很简单的负载均衡器来完成这一功能。最好是有CDN网络让用户连接与其最近的服务器(CDN通常伴随着分布式存储)
2 减少前端链接数:
我看了一下12306.cn,打开主页需要建60多个HTTP连接,车票预订页面则有70多个HTTP请求,现在的浏览器都是并发请求的。所以,只要有100万个用户,就会有6000万个链接,太多了。一个登录查询页面就好了。把js打成一个文件,把css也打成一个文件,把图标也打成一个文件,用css分块展示。把链接数减到最低。
3 减少网页大小增加带宽
4 优化查询:使用noSQL数据库完成余票查询 设计如下:
数据库的count操作并不快,因此对于繁忙季节的繁忙表,每次都count是铁定不行的。我想到的一个办法是:把上面提到的预售车票表加载到内存中。我们用一个64位long类型数字表示一张车票,每趟车的每种座位类型是一个long数组。
对于每个long数字,前面的32位用来顺序存储32个车站(假设一趟车最多有32个站,没查过,不行可以放长点),每一位标记“车票是否包含此站”。如G113 济南到南京的票(车站顺序为第3到第5站),long数字的第2到第4位设置为1,其他前32位设置为0。后面的32位用来表示车票在车票出售表中的唯一编号。这样根据一个long类型数字,我们就能表述一张票的发售信息了。
比如2012年1月13号G113,有软卧500张和硬卧1500张。那就需要两个数组。20120113_G113_软卧 对应一个长度500的long数组;20120113_G113_硬卧 对应一个长度1500的long数组。存储所有售票信息。
有点类似BitSet的感觉,对空间要求不高。我们可以做个系统把所有车票信息按照这种结构加载到内存中。对于实时查票,如查询2012年1月13号G113车次 济南->南京 的余票,就是遍历两个数组,检查位数为2和4的long数字有多少个,就直接获得了软卧和硬卧的剩余票数。对于现代计算机,这点遍历,时间是纳秒级的。
当车票被出售后,从long数组中删除票信息,比如先置为-1表示已经无效。再用后台线程实际删除(避免写冲突,将删除延迟到重建一个数组所消耗的多少纳秒内刚好没有写请求的时间段中)。如果long数组长度为0,那就是没有车票了,直接返回0;用户再怎么刷,也不会干扰数据库。
5 数据镜像(负载均衡)
几乎所有主流的数据库都支持镜像,也就是replication。数据库的镜像带来的好处就是可以做负载均衡。把一台数据库的负载均分到多台上,同时又保证了数据一致性(Oracle的SCN)。最重要的是,这样还可以有高可用性,一台废了,还有另一台在服务。
6 数据分离:
主从复制 读写分离 分库分表
7 硬件云服务
达到动态分配硬件资源,节省开销