又是一年春运时,每到这个时候,世界上总有一个网站会成为大家又爱又恨的焦点。它承载着满满的期待,承担着空前的责任,承受着广泛的批评,却被迫成为这个星球上瞬时访问量最高的网站,没有之一。它就是12306。2012年春运,12306高峰单日访问量达14亿。2013年春运,12306高峰每秒数据库查询量达2.6万/秒。评价12306网站是一件吃力不讨好的事情,首先对其系统架构的了解不够深入,3亿元开发的系统,说实话不是我们能够简单理解的,其次大家已经骂声一片,进行这样的技术讨论,难免有为12306开脱的嫌疑。不过最近看到有关黄牛破解12306网站限制的文章,以及各大浏览器厂商用“抢票插件”来吸引消费者的目光时,我觉得消费者对12306的理解可能已经出现了偏差,是时候写一篇文章来谈谈这件事了。本文将分两个部分,第一部分分析12306网站频频出现问题的根源。第二部分提出我对改善用户体验和售票服务的一些建议。本文权当抛砖引玉,如有偏差和错误,还请各位谅解。
性能瓶颈分析
12306究竟慢在哪里?这是我们首先要弄清楚的问题。每个网站都有自己的痛点,国外网站慢在DNS解析,中小网站慢在网络连接,某些演唱会售票网站慢在登陆,某些电子商务网站慢在查询,12306在以上这几个方面都不慢。铁老大就是铁老大,有充足的资金,使用最高级别的CDN服务,避免了网络带宽问题和高并发浏览问题。2013年以前,12306会在查询余票的时候变得比较慢,但这个问题在2013年的时候得到了根本解决,方法是采用纯内存分布式数据平台GemFire,减少硬盘I/O,增强并发查询,从而将数据吞吐量提高近20倍。当然,这个做法也是有安全风险的,毕竟内存作为主数据存储平台还是非常新的技术,数据可靠性和安全问题不在今天的讨论范围。这个平台最显著的优势就在于大大提高了查询的性能。查票速度快同时说明应用服务器的性能没有问题,这些都是钱能解决的问题。钱能解决的就不是问题。
12306的痛点在于订单。而订单的问题仍然在于数据库。可以想象,在每天放票之前的5分钟,查询请求进入高峰时期,在放票的头1分钟,系统突然转向高写入,而查询请求也同时成倍增加。火车票不同于淘宝购物,淘宝货品的库存只会出现在单一物品页面中,而每一张火车票都可能会出现在不同的查询之中。这就需要一个同步机制,将不同车次的火车票库存在分布式系统中进行转储。这个机制在平常购票中表现良好,但在春运每分钟十万的交易量下,会存在性能瓶颈。前台的余票数额也许可以缓存,但是在提交订单一刹那进行的余票查询必须是实时的,而在上述情况下超过一万的并发就足以让一个大中型数据库瘫痪。12306却只是慢,但基本上挺了过来。这是十分牛逼的系统。
但不幸的是,抢票插件和黄牛党的“技术插队”,给本来负荷很重的系统添加了更多不必要的负担。机器不同于人。人手点击、查看并再点击之间是有时间差的,而这可以给数据库喘息的机会,而机器不长眼,不需要反应时间,这就无形中增加了5-50倍的查询量。而近日出现的黄牛党专业抢票软件更是得寸进尺,在10分钟内提交了1245个订单。大家可以算算,每分钟平均125个订单,而12306就算一分钟处理50万订单(现实中几乎不可能),只要有4000人(这只会在所有购票者中占极少极少吧?)使用这个软件,就必然导致12306网站瘫痪。抢票插件虽然没有达到这个程度,但增加数倍的查询量绰绰有余,数据库处理的查询请求越多,能处理的交易请求就越少。使用抢票插件,适得其反。
当然,所有问题的根源在于供需不平衡,地域发展不平衡等等,这已经不是这篇文章的重点,故忽略。僧多粥少,是中国铁路一直以来面临的实际问题,这不是12306能解决的。
那么,有什么方法能在这个大环境下改善性能,增强购票体验呢?
12306网站优化建议
从技术角度来说,12306采用纯内存数据库,已经属于非常激进的优化方法了,而我并不打算在这方面讲太多,因为交易处理本身就是非常复杂的数据操作。本文将从业务流程入手,以求从根源上解决12306网站的性能问题。
要优化,首先要知道目标是什么。
- 确保网站不瘫痪。我认为这是最重要也是最基本的目标,网站瘫痪了什么都不用谈了。
- 防止黄牛抢票,消除抢票器的优势,减少网站负担。如上文所说,这将大大减少网站负荷。
- 把尽可能多的票卖给需要票的人。这点也很明显,毕竟12306就是用来卖票的。
我认为,达到上述三个目标,有一个简单有效的方法,那就是“预购”。不要看见“预购”二字就想到小米的期货手机,而应该想到另一个每年都会进行的,僧多粥少的活动——高考填志愿。
回想一下,那个时候我们做了什么。首先选出几个心仪的大学和专业,然后根据报考热度和自己的胜算决定顺序。
火车票也可以这么做。
首先选出几个心仪的车次、时间、席位,然后根据车次的热度和胜算决定偏好的顺序,提交预购订单,每个身份证号不超过5个预选车次。预购期结束时网站统一将订单进行处理,根据偏好的顺序逐一匹配车次,如果选择人数超过已有座位,则采用抽号的形式,没抽中的自动进行第二偏好匹配,由此类推。匹配完成后,通过邮件告知消费者订单受理成功,限12个小时内付款,未付款的票进行下一轮预购,直到所有车票售完。
没有抢票,没有刷屏,没有黄牛。为什么没有黄牛?因为系统可以对订单中的身份证号进行批量验证,效率比一般建议的实时身份证验证要高数倍,而且不会对用户体验造成影响,也不会让公安部的数据库挂掉(这很重要!)。而匹配时发现使用假身份证的,直接将账号拉入黑名单,让黄牛无机可乘。因为采用预购,订单提交量应该是比较均匀的,而抢票插件也没了作用,所以能极大减少网站无谓的查询,减少系统负荷。也不用担心票会卖不完,春节永远是一票难求的。
我们来看看以上的三个目标达到没有。网站没有瞬时超高流量,不会瘫痪。黄牛没办法伪造身份证和打时间差战术,减少网站负荷。所有票还是卖出去了。
唯一的不足是,似乎大家购票没有了安全感。摇号?其实你仔细想想,现在的所谓“排队”模式,你能知道你排在第几位吗?5秒钟车票就售光了,很多人根本还没打开页面。而关键在于,这5秒钟内,可能大部分票都是被黄牛抢光了,而不是真正的用户。采用摇号,买到票的几率,甚至比抢票更高。系统可以定期统计预购订单,计算每个车次的购买热度,将粗略信息反馈给用户,而用户可以根据这个信息更加理性地选择一些较冷门的车次保底。另外还有很重要的一点,网络售票只占总票数的一部分,电话和代售点都会预先保留一部分的票,即使网络上的票卖光了,仍然有补救的余地。
当然,以上都只是我的个人想法而已,提供一种思路,有时候看似是技术问题,实际上是业务问题。换一种思路,也许会海阔天空。
牛