抛砖引玉之一 —— 由12306引发的抢购模式的思考
本文不涉及数据库原理,不会简单的对比oracle、mysql、sqlserver这些RDBMS的优异(事实上也很难得出结论),只是基于个人观点引发的一点思考,欢迎拍砖;
一个话题总要有切入点,但这次的切入点显得有些突兀;
事实上,我们是从数据库的负载均衡问题聊起来的。前面的内容不再赘述,只是话题忽的引到12306订单系统如何应对大并发的问题上;
由于没有现成的资料,无法评论12306的应用以及数据库架构是否合理。不过从表象上可以猜到一些倪端:
表象:在春运期间,一般车票是提前N天开始预订,但在放票开始的几秒内被抢购一空
分析:
- 明显的“排队”模式(或者说是队列模式);特点和显示生活中排队购票的情景一样,大家排起长队,放票开始后排在前面的先买到,排在后面的如果正好赶上“票已售完”,那就完成了这轮购票任务,下次请早……这是V1.0
- 通过分时段放票,增加用户排在前面的几率;经历过第一阶段,可能有人发现,如果集中放票,大家都在拼谁起的早,谁跑得快。如果每天只放一部分,那第一天抢到票的人后几天就不会再排队了;或者有人不可能天天都起那么早,于是其他人就有机会买到票了,间接增加了用户买到票的几率;由于这还是基于排队理论,我们姑且叫它V1.1
- 通过多开窗口,提高并发能力;这是大并发环境下的产物。有人发现,购票的人太多了,票也太多了,指着一个售票员,可能20个小时也卖不完,如果下班关窗口走人,又会激怒后面已经排队的人。于是,1个窗口变成8个,同时销售,增加了并发能力;不过也有问题,要是您排的这队前面有个用钢镚买好几张票的,那估计又白排了。不过这个现象在虚拟环境会通过设置超时时间来控制;这个版本是V1.2
经过3个版本的演变,貌似我们的购票系统已经相对完善了很多,抽象化一下就可以开始架构设计、开发了。但事实是真的可以么?
用过12306的同学们,99%以上都经历过春运购票的痛苦,而上面这种购票的模式,在很多场景都被广泛应用,似乎没有什么问题,那问题出在哪里?痛苦的根源在哪里?
=====================华丽丽的分隔线=====================
我们先来比较一下排队模式在现实世界和虚拟世界有哪些差异
- 成本比较
现实世界:最常见就是通宵排队,争取排到靠前的位置,以此来争取在购票环节能抢得先机。要想在这个环节中获胜,身体好、跑得快是关键因素;
虚拟世界:有了软件,很方便的实现了定时抢票的效果,不用人盯着机器通宵达旦(为了避免程序BUG,有时还是需要熬夜手动抢票),时间成本被极度缩减;
效果1:原来排一次队可能要1个小时才能到达售票窗口咨询是否有票,现在可能1分钟甚至更短的时间就能从几百名开外排到售票窗口前,并迅速查出是否有票;
- 并发比较
现实世界:尽管购票窗口有多个,但每个人每次只能选择一条队列,而对于是否能买到票,还存在诸多运气因素,比如前面购票人动作太慢,导致有限的资源被其他窗口先占得,亦或是你前面那个人买下了所有的当次车票等等;
虚拟世界:由于时间成本的降低,以及计算机运算的高效性,单位时间内可操作的指令数增加,排队效率随之增加;简单说,就是原来一次只能排一队,现在只要开多个窗口就能同时排到多个队列中(在实际情况中,往往会通过身份验证等方式限制并发登陆的问题)效果2:原来一个人一次只能排一队,现在一个人可以同时排多个队列;
上面两种,我们称之为客观因素;那其他方面呢?
- 情感因素
为了照顾老幼病残孕以及军人及其他有特殊贡献的人,现实世界中往往会有“绿色通道”或“优先购票窗口”的存在,这是基于道德层面而产生的符合大众道德观念的做法。当然,只要做好“身份验证”这一关键步骤,大众都是可以理解的;
但这在虚拟世界中却很难实现,一个是由于“身份验证”的问题(虚拟世界很难判定符合优先条订票人和实际操作人是否为同一个人,如果选择代购,按照我们的道德观念,也不应该排到优先窗口那一队),另一方面是由于相对于现实世界,有这种需求的群体其比例相当小,而通过网络方式订票,从操作上的最低需求上,基本上屏蔽了这一部分群体;
- 黄牛因素
这可能是差异最大的问题。
现实世界:由于时间成本、人力成本(毕竟雇人排队也是要付报酬的)、处罚成本相对较高,因此从总体样本上来看,黄牛党尽管必定存在,但随着处罚力度的加强,势必会逐步维护大众购票利益;
虚拟时间:根据上面客观因素的分析,黄牛的成本大大降低,而虚拟身份的辨识度问题也为黄牛党制造了更多有利的条件(手上没有现实的统计数据,但我相信黄牛订单无论从数量还是样本占比上,都比现实世界高了很多,甚至是数量级上的差异)
上面两种,我们称之为主观因素;
基于以上因素的考虑,我们可以看出,尽管网络购票的方式有极大的便利性,但直接套用“排队模式”或许会带来更大的问题(黄牛问题最为明显),这就对原有模式中强调的公平性产生最大的挑战,但如何才能做到更公平?
严格意义上讲,公平只是我们在诸多因素影响下想要达到的一种理想化状态而已,这个状态是短暂的,或者说是极不稳定状态,任何一点的因素都可能打破它的平衡性;如果这样看,那不公平或许才是一种常态;
笔者观点:公平并非必然,不公平也并非偶然。
=====================华丽丽的分隔线=====================
既然公平是一种极不稳定的状态,或许我们可以通过一种工具使之趋于的动态平衡,这里我倾向于引入随机性;
简单来说:假设我们在收集的所有样本(这些样本可以理解为某一列次车票的所有订单)中随机选择一些使其获得车票,这或许也是一种公平的描述方式(现实中,在有限资源的争用问题上,“猜拳做主”并非不是一无是处,尽管这被大多数人视为儿戏……)
既然这样,那我们就有了一个方向——通过引入随机性,而使得资源进行离散式的分配;
现实世界中,这种方式也是有实用场景的,比如目前的《北京地区小客车摇号政策》;
这是如何实现的呢?
1、每一期在固定的时间段内(一般是10~50天)接收用户申请信息,并又后台来进行审核,确认申请单的有效性;
2、固定时间(目前为双月的26日),摇号线程将在纪检监察人员的监督和公证人员的公证下,从现场摇号的申请人代表中随机抽取6人,抽取按确定的6人按顺序从左到右排列,从高位到地位随机取6个数字,生成随机种子数,产生摇号结果。
至此,结果生成了,整个摇号的过程完全不存在流量过大的问题,因为申请单已经在几天前都收集完了。
这样的好处有两个:
1、分流申请流量。通过提前收取、审核的方式,将流量分摊到信息收集的窗口的每个时间片;
2、避免某些不法人士通过非正常手段抢在队列前面。由于中签结果存在随机性,而与提交申请单的先后顺序无关,因此没有人可以提前预测结果(程序BUG除外)
看到这里,也许有人会说,购买火车票是刚性需求,和小客车摇号完全不是一个概念。
我有以下2个解释:
1、小客车摇号也是刚性需求。或许在这个月买车还是下个月买车的问题上不像火车票那样紧迫,但从更高一级的层面上看,回家的方式有多种,买不到火车票可以坐飞机、长途车、搭顺风车、甚至跑几个马拉松回去,比购车只能摇号,不知道多了多少种实现的方法;
2、如果将现实世界中的车票购买量转化为虚拟世界的订单量,通过随机方式中签的几率不比你排到前面并买到票的几率低(排队买票的时候,有没有遇到过排在第二位,发现还有两张票,正在庆幸没白等的同时,前面一位拿出几张毛爷爷一晃“两张我都要了”的情形?)
至此,或许我们已经有了一种方案来替代现有的排队模式
1、划定时间段,用户提交申请,并在摇号前完成审核,确认有效订单;
2、增加摇号时的随机性,使结果更为“公平”;
=====================华丽丽的分隔线=====================
话题聊到这里,貌似可以进入总结陈词了,但另外一个问题冒了出来:
如果采用提前提交申请的方式,可能导致大量黄牛多次提交申请,导致有效样本(这里指需要订票,且只提交一次申请的订单)的占比急剧下降,而大量脏样本(形如黄牛订单,一人提交多个,或利用他人身份信息订票但实际不乘车)在随机算法的应用下,获得更多的中签几率,这就公平么?
当然,上面所说的通过随机方法摇号生成中签结果的过程,只是在理想状态下实现的(有效样本即为总样本),在现实中,上面问题提到的情况是必然存在的。因此,如何审核并辨识有效订单就成为这个问题的关键;
在此,由于个人知识层面远没有涉及这么广泛,因此不敢妄断,但我要说的是:在排队模式中,脏样本就不会存在了么?如果脏样本都排在队列的前面(现实中,在春运期间,一张车票放出来往往几秒钟就被抢购了,这其中被黄牛拿到的几率有多大,大家想想就知道了),那就是所谓的公平么?
总结:采用随机方法确定中签订单的方法,在虚拟世界这种大样本量的环境中,比队列模式更能体现公平,而与此同时,还对分散流量有很大的帮助;
而这种方法也适用于各种抢购、秒杀场景(现实中,抢购、秒杀的商业意义远大于其趣味性);
以上仅代表个人观点,欢迎拍砖~