12306.cn网站的思考 (整理篇)

news/2024/5/10 10:47:51/文章来源:https://blog.csdn.net/cjssimei527/article/details/7193217

针对12306.cn网站应用架够的一些看法

背景

针对最近比较热点的列车网上订票系统频繁出现的系统问题,提出了一些自己的看法。

分析

几经分析考虑,认为可能存在几个系统瓶颈。

1.关联系统的系统负载能力比较弱。

2.网上支付的负载能力不够

3.网站本身吞吐量问题

4.网站出口带宽不足

方案

针对以上分析的一些可能的问题点,提出了一些自己的想法

1.关联系统接口问题的话,我的想法是采用排队制。用户登录以后根据车次取号排队,排到后进行订票付款,这样可以减少并发数,保证系统可用率

2.网上支付系统负载不足,可以采用异步。用户订完票以后进入队列,因订票时候是根据实时的数据订票的,因此不会说支付后无票取的情况。队列中的用户可以一次取支付系统允许的人数进行支付操作。完成后用短信或者邮件通知下一批用户登录系统进行操作。在系统可用率提高的情况下,减少了因错误不停操作带来的压力

3.网站服务器问题,可以将重点的功能,如登录和订票两个分出来,投入较多的服务器,其他查询等功能因可使用缓存可减少服务器投入。各个服务之间用sso。登录oid或服务器采用master slave,注册网master 登录等查询用slave

4.网站出口带宽问题,这个没有好办法,可以用在主要的几个城市各部署一套。因铁道部门系统应该是全国联网,因此接口不成问题。这样可以充分利用网络带宽资源。


以上就是我分析出的一些结论,谨用于理论分析探讨。欢迎高人赐教。

思考

  

----

回复网友留言:

回复1楼falconfei

    falconfei您好,手写感谢您的留言。我说一下我的观点

    网站只是一种订票的渠道,因此我猜可能是调用接口,不会直接操作数据库,如果这样订票的核心逻辑应该是早以前就有的,因为还有柜台和电话系统在使用,因此逻辑应该不会改。

    任何系统都有一定的负载值的,一般来讲再厉害的票务数据库也无法承受如此夸张的访问,越是订不到越是点击,越是点击宕的更快。这个恶性循环会一直下去。
所以要只允许所能承受的一部分进来操作,一批完以后再进行下一批。就如火车站春运拿到车票的2小时内发车的先进站。走完一批,下一批再进站。如果不控制,再大的火车站候车厅也难以承受。
取号机制就可以过滤掉一批没有必要的人。取到号的就等着订票,没有号的干脆就不要让他进去点了。只让他随时关注有无余票可取号就OK,读操作肯定强过些操作。而且是没有目的的盲目的写操作。

这个是我的观点

回复5楼 ycc5617

               ycc5617您好,非常高兴看到您的留言。

         对于您提出的疑问,我认为可以在发出通知用户付费的邮件后,规定用户需要在一定时间内(例如5分钟)登录系统支付,如未在规定时间内登录系统,可以认为用户自动放弃,可以回收订单。用户登录后,订单时间调整为固定的时间如2小时,因为电话订票不止2个小时,因此认为2个小时也是恰当的,或者可以1个小时。因为真正有效的用户操作,因此系统更稳定,用户只要操作1次或几次就可以付款。付款收到返回信息后订票成功,否则超过1或2小时,自动解锁释放车票。在队列中可以不记时间,这就意味着锁的时间可能会更长,这个要看支付的吞吐量和速度,然后设定队列的大小和优先级。队列满了,可以让用户排队。

其实一个操作熟练的网友可以在10分钟之内就完成支付,如果是对网络部署的用户1个小时应该也足够了(前提是系统可用性要高)。

         欢迎继续讨论,多谢

回复6楼 ihxwangcong

      ihxwangcong您好,您的留言我已自信看过。您说的架构和事务并发确实是根本性问题,但问题在于解决这个问题不是在个别系统上就能解决的。铁道部的系统也类似于企业系统,是由很多系统构成的。保守估计核心类系统不止一个。从根本上解决这个问题确实是最好的办法。但也是一个耗时耗力的过程。去年我公司进行银行系统的整体改造升级,大大小小的系统几百个。经过几百IT精英差不多一年不休的努力才能够勉强上线。只是备用方案的指定和预演就经过了很长的时间。因此涉及到核心的东西不是不能改,是要谨慎改。在铁道部那边我是这样认为的。暂时宁可舍弃网站这部分,不会丢掉在他们看来比较稳定的核心。除非是遇到很大的问题,无法支撑下去,否则轻易不会动的。

 

铁道部网络购票网站存在的一个大问题

对这个帖子的核心内容作了初步整理,评论前请阅读完成,如有描述不清的请指出,整理的帖子如下:http://blog.csdn.net/dragonimp/article/details/7192777

/*** 以下为这个帖子本来的内容****/

说网站的问题,老早就想说了,元旦前第一次网购买票的时候就想说了,今天上csdn来就写出来分享一下,不过没准已有人发表了。当时看到锁定30分钟提示的时候,仿佛就看到一个让我觉得可以让系统必定垮掉的问题----一个业务级别的超级长的事务!!当时看到网站的做法是下订单就把票先锁定,然后再付款,超过30分钟不付款再把座位返回,愚蠢的是,为了减少购票不成功导致退票的问题,铁道部把解锁时间由原来的30分钟改为45分钟,目前很多人是第一次网购,对网银支付还不熟悉的情况下,这就导致更多的人更长地处于等待状态,不断刷新,需要更多的系统处理。还造成另一个跟严重的问题,就是有大量的票被网站锁定,火车站都买不了,我的这第一次也是目前唯一的一次网购经历就是去售票点买不了,去火车站买,被告知票都被网络锁定了,只能去网站买,于是立刻用手机当网络马上拨号,花了半小时才买到。但是,这锁定的做法对去火车站的极为不公平!电脑可以重新刷新,火车站可不能让你一直占用队列重复刷新啊,就算你愿意重新来,那也得回到队尾重新排啊!

建议去掉锁定机制,改为付款成功才出售座位,与售票点同样的地位就可以了。想到的一种简单方法就是可以让大家先冲值到网站,如果冲完发现没票,则允许转出,如有票,则直接用网站余额购票,就不需要先锁定操作,由于少了锁定时间,很明确当时是否有票,不会存在一会票被锁定,等待超时再放票出来这样重复的事情。这样的话,自然就减少大量pv,而且客户体验会好不知道多少倍。

现在的问题是,好像没看到过银行提供联机转回的功能,转回去都是批量的,但如果用批量的,必然造成普通百姓不理解,但我想这还是值得,以铁道部的风格,不需要大家的理解,也不需要解释,说15天退就是15天,更何况如果批量,可能也就一两天就退回了。所以以更多的退款换来更好的客户体验和更小的系统压力完全值得!而如果不废除这种机制,再加硬件,再并发,算法再优化也是白费劲。

----------------------------------------------------------------------------

2012.1.8 补充总结一下,具体就是把订单锁定机制取消,流程就是:

1、下单选车次,给出需要交费的金额,转入缴费界面进行冲值, 但此时不锁定任何座位。
2、用户缴费完成,再去确认订单,扣冲值的钱同时把座位分配给他。(量大的话可以批量,按缴费时间先后看看都有哪些客户成交)
3、对于缴费完,但由于时间比较晚的,买不到票的情况,允许他把冲值的钱做转出请求。(你们可以晚上批量转出给银行,第二天就能回到客户银行卡上了)
这样好处很明显,不再需要锁定,付款和退款是一个模块,而且可以提前完成,压力就分散掉了。而分配座位是一个模块,可以短时间而且可以批量完成。流程清晰,系统压力小,客户体验好。

这么简单的业务流程不优化,搞什么海量啊分布式啊,什么高并发,什么数据库啊软件啊,都是浮云。别被这些自己都没买过票的,惯性思维的所谓技术大牛们给骗了。

-----------------------------------------------------------------------------

2012.1.8 晚 ,再给大家补充两种图吧,形象一点,不过我不是铁道部的,所以图只用于表示我的意思,不一定完全准确。从图上也可以看到其实修改的东西不多,改的很容易但我想效果是看得见的。

现有购票流程图:因为先锁定,所以大家都要等着是否还有没支付成功的退回来的,剩下一点点就跟秒杀似的,搞死你系统。而且一旦锁定,连火车站都没得买了,因为售票窗口可不能一直刷新,他必须处理其他人的买票要求,这就导致在票没有完全卖完的情况下,可是在火车站就是买不到票了。

我建议的流程图,可以看到去掉了现有流程中的锁定操作,就不会出现票被网上锁定(实际又没卖出去)。买的时候有就有,没有就没有,大家就不会狂刷网站。支付的时候还可以慢慢来,一点都不急,这样你就可以选择任何空闲时间段来先进行下单支付(当然要提前几日的,不然票没有了就没了)。而且在出票阶段,可以用批量,还可以选择各种优先策略,比如车站优先多少,之类的,以起到公平的作用,因为这个时候就是纯出票,处理逻辑很简单,业务就可以更灵活,性能就可以更好。

---------------------

一些问题的解释:

1、关于事务/锁。我承认这个标题那是标题党的做风,但意思只是业务级的"事务"。但从来没有说他们实现用真的数据库事务或锁去锁这个,我想天下没有一个SB会这样做。俺也是写程序的,不会SB到认为铁道部用数据库锁去锁定这条记录或者整个过程是一个数据库事务,就是想要做成数据库的事务,还真不知道这么多页面跨下来怎么实现呢,你们谁见过或实现过?
2、充值的问题。这只是一个概念思路。你可以说是对这个订单进行支付,而不是提前充值。只是在流程上换个位置而已。原来是"出票-支付-不成功退票",现在是"支付-出票-不成功退钱"。注意,现在的锁定你可以看成是出票,因为占据了额度了,效果一样,只不过等会可以退票。
3、这样做法是不得已,避免不必要的压力。因为如果每人只来一次的话,就没有必要在这边刷,系统压力小。现有做法肯定是“以客户为中心”来设计的,但导致了其他的逻辑问题和不必要的并发需求。有的人说如果有多少选择,会付了很多钱也买不到票,这个问题提得好啊。但你系统可以把这个单据标志为退款,同时这个钱退到网站“账户”,还可以直接用来定其他的单子,不需要再次支付啊,当然如果定上,这个钱就不用退了。办法总是有的,不要急于否定。
4、总的思想就是把不必要的访问都减少到最低,分散系统压力。昨天还没人关注,今天至少有人关注了,但不管是赞同还是批评,希望i大家都认真看好内容和我要表达的意思,然后再做评论。

 

 

关于铁道部网站的业务流程改进建议,可减少大量并发请求

本帖对之前发的帖子"铁道部网络购票网站存在的一个大问题----一个大大的事务!!! "进行整理,评论请回原帖,但请认真看完帖子内容,不要再提那些本来已经考虑过并作了解释的问题。

原帖如下:http://blog.csdn.net/dragonimp/article/details/7184319

现有购票流程,优点是:先锁定票,然后再支付,确保客户支付成功都有票。但缺点很多:

1、  票被锁定,但实际未销售。因为支付过程存在不确定因素,可能因为银行系统问题或者本人操作原因或者其他各种原因,没有支付完成。更有可能有人给你锁定了却不支付。

2、  对于传统渠道,只要系统实际票没售出,他就可以出票,但现在一旦余票全部被锁定,此时虽然实际还有票,但现在他出不了,而且他无法跟网上一样在队列等待,他只能回到队伍重新排,但轮到他的时候票可能还是锁定状态,他根本无法买到票。

3、  因为支付结果具有不确定性的原因,没有锁定到票的人,就想尽办法来刷新等待别人没支付成功的退票,对于买票的人,也很浪费时间和资源,需要耗着等。更重要的问题是造成了大量的访问,平白增加了造成大量系统请求,浪费系统资源。我猜为什么12306网站访问量已经到达14亿的原因之一。不管有没有票,买不买得到,本来每个人买票就访问一次就好了,结果现在不知道要访问多少次了。

这里的核心思想就是想办法把现在的访问量尽量减少到每人一次的话,那算下来访问量将可能少掉几十倍。而经过简单的流程调整就可以达到这样的效果,提升性能,减少访问量,收获会比任何海量设计都来得容易,实在。流程优化说明如下:

1、  基本思想:去掉锁定功能。在下单后进行支付,支付完成直接出票,出票时如真的没票了,那就退款。

2、  提前支付:前面的下单和支付过程可以提前完成,这个可以根据情况定,但由于这个过程是提前的,所以大家完全没有必要在一个时间点进行,于是系统压力就分散了,并发需求大大下降。大家也可以从容支付,不要数着那45分钟的时间来完成。

3、  批量出票:在遇到秒杀情况(大量抢同一个车次的情况),出票则可以考虑批量出,也就是收集所有已经支付的订单,按照一定的规则(时间或者有人建议的抽奖的方式都行)进行分配,这个过程处理简单,无论有多少请求,因为是在后台处理,相信性能都没有问题。

4、  批量出票2:下单时可以做个跟银行账户金之类的或股票之类的“挂单”,你支付完钱,就可以把这个单子挂着,系统一旦有票,一旦轮到你了,就给你成交,也就说,你只要交完钱,只要你愿意,你可以把这个订单留着,等着系统给你出票了,但你如果提交得实在太晚,都没有票也可以告诉你,你自己撤单,把钱退到你自己在网站的“账户”下,可以接着下单。

5、  及时退款:由于存在支付完但没票的情况,所以必须能及时给人退款。考虑银行应该都提供批量转出(退款)借口,第二天或第三天即可转回客户帐。典型的比如支付宝的提现功能,好像就是第二天到账(现在还看到一个2小时速体现功能)。而这个过程因为也是批量文件交互,也不存在大家担心的流量啊资源什么问题,这是银行日常问题的业务之一,性能更不在,也没有增加什么成本。而铁道部如果想要实现及时退款,我想他不可能输给支付宝吧,我想这不是技术问题,而是政治问题。

6、  这个流程可以得到的收益就是,每个人只要支付一次,提交一次订单,就能得到结果,不管买不买得到,很快知道答案,也不需要等待,从系统性能来说,那就是减少了几十倍的并发访问需求,系统整体可用率得到保证。但要付出的一个代价就是在秒杀情况下,可能需要退款,但如果及时进行批量转出,这个问题解释清楚也许大家也能支持。

对比两个流程图:

 

 

 关于12306网络购票的架构方面思考

自从2012开始那天,网络购买火车票成了国内最火的话题,12306.cn的Alexa排名从三个月前的全球万位以外迅速窜升至今日的全球排名1560位、中国排名102位。并且成为第11大电商网站。但是由于铁道部公开的种种原因,12306也让人诟病不止。

 

其中最大的原因就是登陆12306慢,页面打不开,好不容易打开了,无法查询票额,无法购买票,甚至只收钱不吐票:),在放票时间更是非常突出。

网上很多网友及专业人士都给出了自己的见解,一下是一些建议截图:

 

 

 

     这些都是业内的专业人士根据其多年经验给出的自己建议。本人虽没有他们那么高深的学问和经验,但是因为也要购买火车票的原因及稍有些经验,所以也考虑了些架构方面的问题,希望和大家分享并讨论。

    在水木社区看到一些人谈内存数据库可以怎样提高多大速度的话题,自己不太支持,首先12306并不像普通的互联网网站,可以允许一些差错,只要误差在合理范围内,不会影响很大。但是像银行及12306这种涉及用户钱或者珍贵的火车票,我想很难容忍因为内存数据库崩溃导致的一系列问题。

 

一 静态资源的压缩优化及CDN分发策略

   12306上涉及的图片及js、css等静态资源应进行压缩后传输,设置expires属性,在浏览器端缓存,减少对静态资源访问,提高页面访问速度。

   同时高效使用CDN分发策略,像北上广等一线城市应尽量分流,减轻服务器压力,防止服务器因压力过大宕机或IO低效 崩溃。

二  缓存车次信息及余票

   用户登上网站后,除了登录操作流程外最火的两个操作流程应该是购票和余票查询。余票查询应及时给用户返回查询信息。所以需要优化缓存结构。车次票价等信息因为不会发生经常性的变化,所以应常驻内存,结合cdn分发策略,将用户引导至最近服务器,返回查询信息。余票数据因为涉及到需要和当前售票情况相关,所以应在每卖出一张票后同步更新缓存数据.这里需要注意的是查询余票只需要读缓存即可,在缓存存在情况下不需要去访问数据库,同步缓存在买票阶段再说明。如果缓存没有可以直接访问数据库,如果访问分流设计到位,相信缓存穿透情况会比较少,也不会对数据库带来很大压力.

三  按车次进行购票队列设计

    因为国内火车票热度关系,同时并发购票情况会非常突出,目前没有看到12306有队列的排队机制,难道网站设计者想让用户立即购买票么?!这个有些疯狂,这就导致很多人上去点购票,却打不开等等。

    我的想法是按照车次进行队列设计,并在缓存中维护这些请求队列.一个用户过来比如买K51车次,系统应从后端缓存中获取该车次缓存信息,并将该用户id加入队列末端,设置时间戳,并返回给用户前面有多少人等信息。维护该队列的服务器应作为后端的一层进行设计,防止一个服务器崩溃导致用户无法访问或者直接穿透到下一层。用户浏览器可以1s为单位像这些缓存层访问,缓存队列接收到后同步更新队列中该用户时间戳。对于长久没有请求的id有过期清除机制.目前一般火车车厢15-20节左右。YW25G(硬卧)定员一般66人左右,YZ25G(硬座)定员118人,RZ25C(软座)定员80人,RW25(软卧)定员36人。所以每辆火车人数在1000-2000左右.当然买票的人数可能会超过这个数值,每天买同一车次人数也不会是一个天文数字。

 

四 售票逻辑

售票处理只负责从前面的队列中获取买票的用户id,并发卖多少张票视情况处理。这里涉及到铁道部以前的票务系统接口,很多业内人士也反映压力最大的就是该接口调用。假设并发处理可以容纳20个(这个值因为不是内部人士,无法确认,仅是假设),则取队列中20个id,进行并发处理。就像火车站开通了20个窗口一样,对来的20个人进行售票服务,直至完成.可能这个过程可以有优化的地方,因为毕竟每个用户花在真正买票的时间不一定,有的短,有的长。买票流程应尽可能优化,尽量缩短用户购票需要的时间,提高购票速度。

售票处理得到票务处接口返回后,即同步更新该车次余票缓存,返回给用户购票信息。

五 票数据库设计

火车票数据库层应该是使用铁道部以前的票务系统,这种底层的数据库就像银行一样不会随便变更,要知道很多银行系统等数据库设计基本是90年代由IBM等那时设计的,猜测铁道部可能也会类似这样。所以作为12306等这样的外层服务,只能调用其底层的接口做一些操作。

再回到上面谈到的票务系统接口,个人觉得应尽量减少该接口的调用。目前火车购票主要有三种渠道,售票窗口(火车站及各售票点)、电话购票、12306。下面设想可能不是合理,只供大家讨论。如果这三种渠道购票比例为40%,20%,40%(这个比例可能会调整),则完全可以确定网上购票每个车次票数。

如果确定,则可以根据车次进行分库。数据库层包含一些列数据库,每个数据库可能负责多个车次信息,具体车次数量由测试压力确定。售票操作由之前调用统一的票务接口转为了在各车次数据库操作。当然票务接口也会去访问后端数据库,貌似没有不同,但是这样处理后数据库压力已经分流,网站购票只要关心分配好的这些车次数据库就好。像热点车次也应该考虑请求会比其他普通车次要高很多情况,采用更高端的服务器进行处理,相信硬件在铁道部应该不缺.

售票层次应处理好对车次票额的同步机制。任何情况下,只允许同一车次同一个人来买,保证票数的稳定.

最后,总结一下自己的思想,主要是靠架构分层思想,将12306层次分为CDN分发层、静态资源处理层、动态资源的缓存层、排队缓存层、售票层及底层按照车次水平划分设计的数据库层,最终思想要靠分流、有效排队机制及车次水平划分设计数据库等减少对系统服务器的压力,同时保证购票的准确性。

 


 从铁道部12306.cn网站漫谈电子商务网站的“海量事务高速处理”系统

 

首发地址: http://bbs.hpx-party.org/thread-8488-1-1.html

 

采访新闻上了新浪的首页 http://tech.sina.com.cn/i/2012-01-11/00416623854.shtml


采访新闻上了腾讯的首页 http://finance.qq.com/a/20120111/000728.htm


我在新浪微博上转发了几条已知的预订火车票的技术漏洞 http://www.weibo.com/443089607


文章比较长,成文仓促,结构的确不晴晰,向各位读者致歉,写一个本文导读吧。整篇文章论述的就是“海量事务高速处理”的经验和误区。


第一部分论述“海量事务高速处理”现阶段没有通用解决方案,尝试通用解决方案就是误区。


第二部分讲解算法问题、安全问题经验,以及一些误区。


第三部分讲解电子商务网站的核心交易系统如何随着网站的发展而演进,分成了三个发展阶段,发展过程中的一些经验和误区。


另外,具体的需求的确不在本文讨论之列,望各位读者海涵。

今天你买到票了吗?

12306.cn是中国铁路客户服务中心网站。作为铁道部唯一授权的火车票订票网站,在2012年的春运前夕几乎成为了一个家喻户晓的网站。因为从今年起,每个人都可以通过这个网站以实名制的方式预订火车票,和家人团聚,共度一个祥和幸福美满团圆的春节。与此同时,12306.cn网站也被舆论推到了风口浪尖,这并不是因为12306.cn网站满足了每一位用户回家的愿望而获得了赞誉。而是在互联网已经开始进入每个人日常生活的时代,12306.cn网站的界面丑陋、UI(用户界面)粗糙,不夸张的说,比十年前的网站还逊色。当然,作为一个功能性网站,用户也不会苛求界面的美观,UI的精致,但是让每一位用户都不可接受的是,12306.cn网站的服务器不稳定,屡屡瘫痪。笔者很荣幸应CSDN之邀撰文对本次事件做一些分析。

作为政府部门唯一授权的网站,用户没有用脚投票选择离开的权力。刚刚过去的2011年是中国电子商务网站遍地开花的一年,中国的每家电子商务网站都在比拼烧钱打广告,期望获得更高的全球Alexa排名,期望获得更高的订单数量、销售数量、用户转化率。按着笔者了解的情况,在2011年,电子商务网站每IP的广告费用平均约为0.4元,转化为注册用户时的每注册用户的广告费用平均约为4元,转化为实际销售的每个首次销售订单的广告费用平均约为40元,也就是说一位通过电子商务网站广告而访问电子商务网站产生的首次购买,如果利润低于40元的话,那么就是在赔钱。

如果从电子商务的角度来看12306.cn网站的话,情况正好相反,没做一分钱广告,仅仅几天的时间Alexa的排名飙升至260,这不是中国网站的排名,是全球网站的排名,而且还有不断上升的趋势,日订单量很可能成为全国第一,销售额都是可预知的,因为每列火车中每节车厢的每个座位都会卖出去,转化率达到了前无古人后无来者的100%,因为所有的注册用户,都是想买车票的,只能是他买不到,不可能是他不买。媒体普遍戏称12306.cn网站是中国、仍至全球有史以来最牛的电子商务网站。

作为12306.cn主管部门——铁道部,从建国之初就有一个众所周知的外号“铁老大”。但是作为12306.cn网站的制作单位——中国铁道科学研究院(简称铁科研),从一家仅为业内人所熟知的科研单位,仅仅几天的时间就受到了广泛的关注,因为每一位在订票时屡屡遇到服务器不稳定、甚至瘫痪的用户,特别是前一秒中还看到有票,因为进不去订票界面,后一秒钟就看到无票的用户,都会对这个网站的制作者产生好奇,究竟是谁做出这么一个网站?浏览到12306.cn网站页面的页脚就会看到“中国铁道科学研究院”的名字。接下来笔者将分析研发一下类似于12306.cn网站将会遇到哪些问题,以及如何通过现有的技术手段解决这些问题,并探讨在一般的电子商务网站中如何处理同类问题。

第一部分

在线处理的四种类型

互联网站除了浏览器端的展示外,在服务器端的程序归属于“在线处理”的范畴。一般来说“在线处理”可以分成“在线事务处理”(OLTP,OnLine Transaction Process)和“在线分析处理”(OLAP,OnLine Analytics Process)两类处理方式。事务(Transaction)这个概念来源于数据库,在数据库中事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

随着技术的发展,事务已经不仅仅局限在数据库领域。现阶段,一般用两种角度来描述一个事务,一个是从外部的角度,事务是恢复和并发控制的基本单位。另一利是内部的角度:事务,是由一系列不可分割并且不可错序的动作组成。虽然理解事务的角度随着技术的发展不断演讲,但是用于描述并评估事务的属性保持不变,一个事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

  • 原子性(Atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
  • 一致性(Consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
  • 隔离性(Isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(Durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

以12306.cn为例,为避免“黄牛”,购票系统有一个业务逻辑:一个有效身份证件同一乘车日期同一车次限购一张车票。因此购买一张车票可以简化为包含四个操作:

  1. 判断同一乘车日期同一车次是否有未预订的空余座位
  2. 判断这个有效身份证是否已购买过同一乘车日期同一车次的车票
  3. 车票上标注的座位标记为已预订
  4. 如果没有购买过,则该身份证预订一张车票

原子性是指用户提交一次购买的时候,要么该车票上标注的座位标记为已预订并且该身份证预订一张车票;要么没有标记该车票上标注的座位已预订并且该身份证预订失败。也就是第3个操作和第4个操作要么都做,要么都不做。不允许没有标记该车票上标注的座位已预订,但是该身份证预订了一张标注为这个座位的车票,或者有某一个座位被标记为预订但是该身份证预订失败。一致性也是指类似的含义。

隔离性是指如果有两个用户同时预订同一乘车日期同一车次的车票时,假设只剩一张票了,那么第一个用户判断出有未预订的空余座位,那么他就可以成功预订车票。因此既便是第二个用户在第一个用户标记该座位已预订之前判断是否有未预订的空余座位,返回给他的结果也是没有空余座位。

持久性比较好理解,如果一个用户已成功预订了一个座位,那么其他用户就不能预订同一乘车日期同一车次的同一个座位了。

对于一般的电子商务网站来说,一次购买行为可以简化为四个操作:

  1. 判断该商品有库存
  2. 判断该用户的账户余额
  3. 减少该用户的账户余额
  4. 减少该商品的库存

这样的四个操作组成了一次购买行为,也需要满足ACID属性,当然实际的场景要复杂得多。

一般来说,不具备ACID属性的在线处理都可以称之为OLAP,这不意味着OLAP比OLTP简单。通常所说的OLAP是指对一定数量的数据进行统计分析的操作,需到强大的计算资源支持。OLTP和OLAP是评估“在线处理”的一个角度,另一个角度就是对于处理速度,也就是响应速度的要求,速度一般和数据量紧密关联,相对于海量高速处理而言,海量低速处理,或者少量高速处理就容易得多。通常把海量低速处理或者少量高速处理统称为低速处理。

这样对于在线处理的两个角度就构成了四种情况:海量事务高速处理,海量分析高速处理,事务低速处理,分析低速处理四种情况。

 

OLTP

OLAP

海量高速

海量事务高速处理

海量分析高速处理

低速

事务低速处理

分析低速处理

“海量事务高速处理”与其他在线处理的区别与联系

在这四种情况中,先讲一下分析低速处理。虽然分析低速处理看起来不要求速度,也不要求事务,但是在在线处理中被纳入到分析低速处理领域的问题一般是指复杂算法方面的处理,常见的有聚类分析,在本文中不再展开讨论。下面分别针对海量高速中的OLTP和OLAP的区别展开探讨,以及OLTP中的海量高速和低速展开探讨。

对于海量高速而言,因为涉及到相当规模的运算量,远远超过单台计算机的处理能力,需要多台机算机组成一个系统,对于外界来说就像是一个系统,这样的方式被称为集群计算。集群计算除了用于解决运算量之外,同时也用于提高系统的可用性,当集群中的一台计算机出现故障时,另一台计算机可以接替它的计算任务,从外界来看,集群相对单台计算机而言,可用性提高了。

在OLAP中,因为每个在线处理过程之间都是相对独立的,不具有OLTP的ACID属性,因此使用集群计算处理分析任务时,一般的过程是把任务分发到多台计算机上,所有计算机返回计算结果后,再汇总结果返回给用户,这种方式一般被称为高速并行计算。从字面意义上看,所有的计算任务都是并行处理的,之间没有太多的依赖关系。对于高速并行计算而言,只要有足够的传输带宽、服务器够快、够贵、够多就可以解决所需要的计算量的要求。

这也是目前“海量事务高速处理”混同于“海量分析高速处理”时常见的一种误解,认为使用“高速并行计算”解决“海量分析高速处理”的方式可以用于解决“海理事务高速处理”,比如说使用单台服务器一秒钟可以处理一个交易,那么使用一万台服务器就可以一秒种处理一万个交易。或者说是只要有足够的传输带宽、服务器够快、够贵、够多就可以解决“海量事务高速处理“的问题,这也是本文要澄清的关键问题之一。这也是相当一部分电子商务网站从初期的低速处理时期向“海量高速”发展时遇到的最大技术瓶颈。

当然这并不意味着“海量分析高速处理”比“海量事务高速处理”容易,这是两个不同的方向,一个典型的例子就是搜索引擎,大型搜索引擎中的一次搜索行为并不会涉及ACID等等属性,但是仍需要将一次搜索任务分发给数百台或者更多的服务器,然后再合并这些服务器的搜索结果后返回给用户。在这方面典型的技术就是Google的MapReduce编程模型,目前有Hadoop这个开源项目实现了Google的MapReduce模型。

“海量事务高速处理”从量变到质变

由于事务具有ACID等属性,因此“海量事务高速处理”和“海量分析高速处理”需要完全不同的技术路线,在国内,12306.cn并不是第一个遭遇这个问题的网站,2008年奥运会的订票系统也遭遇过同样的窘境,只是因为用户量相对少些,和大多数人的关系不密切而没有得到广泛的关注。当然如果数据量没有那么多,速度要求也没有那么高的话,也就是在“事务低速处理”领域中,目前有着丰富的解决方案,目前主流的数据库,特别是商业数据库都重点关注这一领域。

特别是从具体的需求来看,“事务低速处理”和“海量事务高速处理”只是“量”上的区别,作为需求的“事务”本身并没有任何变化,因此一个简单的思维就是开发一个“事务低速处理”的网站,然后用“海量分析高速处理”的高速并行计算解决方案来解决“量”问题,但是结果并不如意,在辩证法中的三大定律之一——量变引起质变,也同样适用于“海理事务高速处理”。近些年来,已经有很多先行者尝试过努力,也积累了一定的经验和教训。

在通用领域中,既便是作为领头羊的IBM、HP等公司碰到这种系统,都是只卖硬件,绝不为软件系统承担任何风险和责任。说明白了,我挣硬件的钱,软件,你们谁不怕死的话谁就向前冲吧。多年来在通用领域毫无建树不意味着“海量事务高速处理”是不可解决的难题,在专用领域“海量事务高速处理”的发展就非常引人注目,其中最典型的案例就是IBM为大型金融机构提供的IT解决方案。分析这个案例有助于拨开“海量事务高速处理”的重重迷雾。

在IBM的解决方案中,其核心就是S390大型机,笔者虽然没有接触过S390大型机,但是曾经在十年前学习过AIX小型机,并取得了中级管理员证书。在这里不展开讲解具体的小型机、大型机技术,总体而言,这些设备所表现出来的卓越运算能力,都是局限在某个特定的领域。也就是说,IBM为金融领域的特定场景“定制”了一套系统,这套系统在硬件、操作系统、数据库、中间件、应用程序整个流程的每个环节都做了优化,消除了所有的瓶颈。

换句话说,虽然在这套系统中仍然可以区分出硬件、操作系统、数据库、中间件、应用程序。但已经和通用领域中的含义不同了。比如说S390上运行的数据库是DB2,事务中间件是CICS,在普通PC上也有着对应的DB2和CICS产品,但并不是简单的移植,在S390上的这些软件通过和硬件、操作系统紧密结合从而表现出卓越的性能,换句话说,在普通PC上的DB2和CICS等产品仅仅是提供给开发者便于学习和开发而已,脱离了IBM的专用硬件,这些软件的表现明显欠佳。

通过S390的例子可以看出,在专用领域中,“海量事务高速处理”需要按实际的需求“定制”,目前以及未来相当长的一段时期间不会出现通用的“海量事务高速处理”的解决方案,更不会出现相应的通用软件。当然一个现实的问题是,在很多领域中,并不会都像金融业那么有钱来支撑硬件的研发,比如说电子商务领域,既不能像金融业那样来支撑硬件的研发,同时业务量又相当于一些小规模的银行。此时就需要考虑如何在通用硬件上,借助于“定制”操作系统、数据库、中间件、应用程序来解决问题。

浅淡事务的隔离级别与锁

前面谈到了解决“海量事务高速处理”需要定制,那么接下来就需要考虑这个定制过程的核心问题是什么?要“海量高速”,就要能并行处理,而且是多台计算机并行处理,此时与事务的ACID属性关系最密切的就是隔离性。也就是说当多事务同时进行时,两个事务之间的影响情况,一般来说隔离性需要处理三个问题:脏读、不可重复读、幻读。

  • 脏读:一事务对数据进行了增删改,但未提交,有可能回滚,另一事务却读取了未提交的数据
  • 不可重复读:一事务对数据进行了更新或删除操作,另一事务两次查询的数据不一致
  • 幻读:一事务对数据进行了新增操作,另一事务两次查询的数据不一致

以预订车票为例,脏读就是当一个预订车票的操作中,标记了某个座位已预定,但是没有为该身份证预订一张车票时,其他预订车票的操作读取该座位的状态时,不会立刻获得该座位已预定状态,而是当第一个预订车票的操作完成后,获得该座位已预定状态,或者当第一个预订车票的操作回滚后,获得该座位未预定的状态。读者可以参照不可重复读的解释构照相应的场景。

一般来说事务都需要禁止脏读和不可重复读。而对于幻读就需要依赖于实际的需求展开分析,以预订车票为例,当你查询余额的时候,看到车票有余额,但是进入预订的时候,发现没有余额,如果把你的整个操作视同一个事务的话,这就是幻读,当然一般对于用户来讲是不禁止幻读的,但是在交易系统内部则常常要禁止幻读。

在现代的数据库系统中,一般可以为事务直接设置隔离级别,以期避免相应的问题。最高的隔离级别就是串行化,也就是相当于“一个一个执行”。在单机测试中,串行化的性能低至禁止不可重复读但允许幻读时的30分之一,这也就是禁止幻读的代价。对于多台计算机而言“一个一个执行”相当于单机的效果,没能体现多台计算机的计算能力,是不可接受的,此时就需要采取其他的办法。目前主要有两个策略来解决这个问题。

以预订车票为例,串行化就是指所有的预订车票操作一个一个处理,看上去这个方式很笨拙,其实在现实生活中的排队就是典型的串行化。在现实生活中,经常会有通过预分配资源的方式,来创建多个排队来提升速度,例如在火车票还是一个小硬纸片的时代,火车站的售票大厅中每个窗口销售不同车次的火车票,这就是预分配资源,买票需要先按照车次选择窗口,然后排队购买。有过经历的读者马上就会发现,虽然预分配资源可以通过排多个队来提升效率,但是如果预分配的方案不合理,则会造成一个队排得很长,而另一个队没有人的情况。进一步的,预分配资源的方案无法避免一个人排了一个队之后,再排一遍,或者排另一个队。

一种是通过建立“快照”的方式,在需要避免“幻读”时,就创建一个快照,此后这个事务中的所有读取的操作都是针对于这个快照进行操作,因此就不会有“幻读”发生,当然在数据库中实现快照的方式并不是真的复制一遍数据库,而是通过记录数据的时间戳的方式来实现,对于单机来说,需要额外的存储和计算来记录并处理时间戳,对于多机来说,保持时间戳的同步也需要相当的代价,因此一般仅用于特定的场合。

通行的设置隔离级别的方式是加锁,锁的情况有很多种,而且不同的数据库的产品中的实现方式也不尽相同,在此不展开讲解,一般分成三种情况,数据库按照语句加锁,带有加锁命令的语句,在声明事务的同时声明隔离级别。需要注意是锁会导致死锁。此时应用中两个或多个事务发生永久阻塞(等待),每个事务都在等待其他事务占用并阻塞了的资源。例如,如果事务A锁住了数据1并等待数据2,而事务B锁住了数据2并等待数据1,这样两个数据就发生了死锁现象。

以预订车票为例,当查询该身份证是否已预订过相同乘车日期相同车次的车票时,就相当于给这个身份证加上了锁,直到预订车票的操作成功或者失败才解锁,在此期间其他查询该身份证是否已预订过相同乘车日期相同车次的车票的操作都被阻塞(等待)。当查询该车次是否有空余座位时,也就相当于给这个车次加上了锁,直到预订车票的操作成功或者失败才解锁,在此期间,其他查询该车次是否有空余座位的操作都被阻塞。

当发生死锁后,就需要解除死锁状态,否则更多事务在请求处于死锁状态的数据时,就会发生连锁反应,解除死锁状态的主要方式是选择回滚其中的某一个事务。解除死锁毕竟是一种消极的处理方式,积级的处理方式应当是预防死锁、避免死锁,同时辅助以检测死锁避免出现连锁反应。在现代的数据库系统中,一般都提供各种加锁的方式以及比较智能的处理锁。对于支持多台计算机部署的场景中,也会把锁延伸至多台计算机中,也就是说,一台计算机上的数据库加锁的时候,同时会影响到其他计算机上的数据库,从而保证在多台计算机上配置成一套数据库系统时,运行在不同计算机上的事务的隔离级别和运行在单台计算机上的隔离级别表现一致。

第二部分

电子商务中事务的核心算法问题

在电子商务的场景中,因为涉及到财务(钱)的操作,就需要保证事务的隔离级别足够高不会导致出错。在实际需求中,无论是钱的余额,还是待售商品的存量,都会涉及到在一个表中查询记录并求和这样的操作。如果应用将一个操作直接请求到数据库时,为避免在并发操作时出现两次查询的数据不一致的情况,就需要隔离级别中禁止幻读。而隔离级别禁止幻读时在多台计算机上的的性能严重下降,难以满足要求。这种现象说明不适合借助于数据库本身的锁机制来实现电子商务中“海量事务高速处理”的请求(对于数据库本身支持一定的中间件特性的情况按照中间件来讨论)。

既然应用直接访问数据库不适合“海量事务高速处理”的场景,就有必要在中间增加中间件,把事务的协调处理交给中间件处理,由于计算量大,这个中间件需要部署在多台计算机上,共同构成一个分布式事务中间件。目前市场上有很多支持分布式事务的中间件容器,例如EJB,可以通过简单的配置和编程就可以获得所需要的事务隔离级别。但是在电子商务的实际场景中,如果使用容器提供的分布式事务将会遭遇和在数据库中直接实现时相同的困境,如果不依赖于容器本身的分布式事务,而是按照需求自行管理锁的话,容器本身不仅没有起到积极的作用,而且因为引入了额外的处理过程而大大降低性能,因此目前世界上上处理速度最高的海量事务处理系统中,基本上都是自行开发。

自行开发分布式事务中间件,可以按照实际需求最大程度的优化,自行开发也不意味着没有规律可循,目前在“海量事务高速处理”中自行开发分布式事务大多基于Paxos算法。http://zh.wikipedia.org/zh-cn/Paxos%E7%AE%97%E6%B3%95 Paxos算法的基本内容可以参考维基百科上的介绍。本文不重复理论知识,仅探讨一些在实践中可能涉及到的问题。对于没有接触过Paxos算法的朋友,首先要理解Paxos是一个怎么样的算法,Paxos算法并不像JPEG、PNG、MPEG等等算法,Paxos算法提供了一个为分布式系统如何就某个值(决议)达成一致的模型。Paxos算法证明了一个符合Paxos模型的实现必然能保证分布式一致性,不需要针对于每次的具体实现再次证明,当然,如果有时间和精力的情况下,证明一次Paxos算法有助于加深对于该算法的理解。其次要知道Paxos算法是目前解决分布式系统一致性算法中最有效的算法。

刚才提到Paxos算法解决的是分布式系统一致性,而实际场景中从分布式事务到分布式系统一致性还需要按照具体的情况拆分事务。这个拆分过程需要反复论证,任何一个环节的设计缺陷都将导致整个分布式系统一致性失效。如果您刚才已经看到了Paxos算法的简要介绍,您可能会注意到两个细节,在Paxos算法中值是保存在某一个分布式节点上,每个节点中保存的值允许是不同的,因此对于获取值这样的操作也是针对于某个节点的,放在实际的计算机环境中也就意味着,数据库被绑定在中间件上,其他的应用和中间件都从相关的中间件上获取数据,而不是访问数据库。第二个细节就是提案依赖于编号,因此在实际的计算机环境中需要保证一个能满足海量事务的编号机制。

安全问题与优化思想

除了算法问题外,还需要特别关注安全问题,“海量事务高速处理”的安全问题主要是在系统负荷暴增的情况下,或者有若干台服务器宕机时,如何保证整个系统只是慢下来,而不是崩溃。一个针对类似问题的研究曾经引起美国政界的轩然大波,一位来自中国的留学生发表了一篇《如何对美国电网的缺陷进行梯级式攻击》的论文,其核心思想就是如何用最少的代价引起一个局部系统故障,而局部系统的故障可能导致更大范围内的系统故障。在分布式系统中普遍存在这个问题,而对于基于事务的“海量事务高速处理”则更应重视这个问题。再举一个计算机的例子,Linux操作系统有一个Load值,这个值代表着一段时间内平均需要处理的进程数,保持计算机能及时处理进程的话,Load值应为总内核数的70%,而Load值超过总内核数的100%的话,计算机的性能不会获得提升,相反因为CPU需要花费更多的时间在进程调度上。

以预定车票为例,如果一个系统每秒种能处理一千次交易的话,那么一般来说,如果有700次交易随机分布在这一秒钟提交到系统的话,有一半以上的交易提交到系统的时候,系统正处于空闲状态,可以立刻处理。如果有1000次交易随机分布在这一秒种提交到系统的话,那么所有的交易都要先等待之前的交易完成后才能被系统处理。从系统的角度来说,不仅需要在处理交易的同时,阻塞后续的交易,同时还需要在完成一个交易后,选择一个没有和目前正在处理的其他交易有冲突的交易,这种判断自然要比系统空闲时不需要判断麻烦得多。如果负荷继续攀升的话,系统需要不断的阻塞后续的交易,反而减慢了正在处理的交易。目前12306.cn网站可以简单按照这种思路来理解。

刚才提到了在“海量事务高速处理”系统中,数据库已经被融入了中间件中。而中间件的设计基于Paxos算法,与传统意义上基于中间件容器的设计不同,一些在中间件容器的模型中放在中间件的功能在“海量事务高速处理”系统中可能放在应用中实现,也有可能正好相反,一些在中间件容器的模型中放在应用中的功能在“海量事务高速处理”系统中可能放在中间件中实现。更进一步,操作系统也需要按照实际的应用和中间件调优。这意味着在“海量事务高速处理”系统中,从应用到中间件到数据存储到操作系统都是一体化考虑的,唯有如此,才能达到高速。

形象的说,“海量事务高速处理”系统最后往往分不出哪一块是应用,哪一块是数据库。换言之,如果能像通用系统一有明显的应用、数据库、操作系统、中间件的界限的话,其实就失败了,因为没有优化到极致,用武侠小说的话讲以无招胜有招,通用系统就是“有招”,而“海量事务高速处理”系统必须做到“无招”,当然了,也可以称之为“屠龙之技”,因为国内应用场景很少,在国外也主要是大型企业可能涉足这个领域。

不必重蹈覆辙

既然整个系统是一体化定制,就必然会导致牵一发动全身,在实际环境中,特别是互联网瞬息万变,需求不可能一成不变,这时在需求环节中就需要精准分析需求,同时在前期要考虑前面提到的算法问题和安全问题。因为在整个后面的过程中,核心需求是定死的,不可能有任何变化的,而且部署和运维也纳入到研发中的全部定制。这么多因素一起考虑,要定制中间件、操作系统和数据库,可想而知开发难度有多大了。

在实践中,特别是在没有遇到瓶颈的时候,一个通用系统的解决方案,比如说Linux + Oracle + J2EE + Tomcat 更容易获得认可。而在遭遇瓶颈后,因为整个系统的架构已经定型,全面提升为“海量事务高速处理”系统不仅有研发的投入,还有数据遗留资产的升级等等问题。最后往往采用牺牲局部的方式不停的打补丁来解决。这也是目前国内很少见到“海量事务高速处理”系统的原因。毫不夸张的说,国内多数发展迅猛的电子商务企业都正在面临这样的困境,可以预见是否有决心定制“海量事务高速处理”系统将成为这些企业能否胜出的决定因素。

EJB方案之所以不适合,是因为所用的Oracle + J2EE + Tomcat都是通用的工具,里面有大量的为了符合通用标准而具有的模块,这些模块虽然让这些工具可以适合在多种场景下应用,但在特定场景下却成了影响系统性能的垃圾,当这些“垃圾”需要清除的时候,目前的软件公司基本上束手无措。

当然,不采用EJB方案不代表没有中间件,前面提到的Paxos算法,在实践中也是以中间件的形式体现,当然,在这种场景中的定制开发的中间件已经和通用方案中借助于中间件容器实现的中间件已经大不相同,但是有一点要值得注意,所有的“写”操作,都是借助于中间件来完成的,而不是借助于数据库中的事务操作。

从大量的经验教训来看,对于已经预见到“海量”的电子商务网站,不要采用EJB等通用中间件容器方案;而对于有着“海量”发展预期,但是目前还没有达到“海量”的电子商务网站,核心业务的所有的“写”操作要借助于中间件而不是数据库。通常“海量事务高速处理系统”造价昂贵,应用范围不广,除了电子商务公司自行研发的系统外,目前涉足该领域的研究机构也非常少,清华大学web与软件技术研究中心是中国极少的研究此技术的权威机构,有宝贵的成功经验。

第三部分

“海量事务高速处理”的演进道路

前面讲了一些经验教训,在实践中很少有像12306.cn这样的可以预见到“海量”的电子商务网站,更多的有着“海量”发展预期,但是目前还没有达到“海量”的电子商务网站,这些电子商务网站一方面受客观因素制约不可能一步到位设计“海量事务高速处理”系统,另一方面发展期间同时也是业务探索期间,也不太可能明确哪一块业务将发展成为“海量”。此时就需要在实际建设之前规划一个演讲的道路,避免陷入误区。下面讲一下“海量事务高速处理”的演进道路。

首先要特别重视需求,既然核心系统将是全部定制开发,因此需求变更如果影响到了核心系统的话,那么代价将是非常昂贵的。所以要尽可能的精确调研需求,避免模糊需求影响到核心系统,下图就是广为流传的由于需求理解的偏差,导致最终结果的严重偏差。


如果定性的话,曾经有一个研究,一个缺陷如果在需求阶段修正要花1美元的话,那么在设计与撰写阶段要花2美元,如果是在完成后修正的话,平均会花费69美元,如下图所示。这还是针对项目而言。由于互联网网站的升级必须要继承所有的数据遗留资产,因此互联网网站修正的代价将更加高昂,而对于处于核心的“海量事务高速处理”系统来说,严重缺陷的修正代价可能是不可想象的。


电子商务网站产品设计基础

既然需求对于电子商务网站是如此重要,那么该如何精确的分析需求并避免错误呢,一般来说,可以将一个网站分成如下图所示的七种产品型态。


这七种产品形态可以用如下的经验方式界定。


对于基本的电子商务网站来说,主要包含CMS、MIS、OA、ERP这四种产品形态,这四种产品形态在电子商务网站中的常见体现形式如下图所示。


从图中可以看出,核心交易系统的需求是ERP中的一部分。下面继续分析ERP产品形态。一般来说ERP系统有三个层面——Data、Process、Action,大多数的ERP系统实现了Data和Process二个层面,Action目前尚处于探索阶段。如果用一种简单的方式理解的话,Data就是与核心交易系统的MIS,而OA就是与核心交易系统的OA,如下图所示。


通过上面的介绍,读者可以看到,电子商务网站产品设计的核心之处在于如何分析出核心交易系统的需求,换句话说,如果在产品设计阶段就不重视核心交易系统的话,那么在未来也将投入巨大的成本在修正缺陷上。

初期核心交易系统程序设计示例

前面提到,为了长期的发展,从一开始所有的核心交易的“写”操作都应当通过一个交易中间件,从架构模式上来看,属于Blackboard“黑板”模式。在实践中,一开始由于需求变化频繁,在没有特殊要求的场景中,“读”操作可以直接读取数据库,为了缓解压力,也可以借助于数据库的复制功能,下图就是一个核心交易系统中间件的部署示意图。


由于需求随着发展将不断变化,因此一开始很难有清晰核心交易系统的边界,所以在程序设计上采用接口设计方式,设计接口需要遵循三个标准:

  • 按照不同来源划分接口
  • 接口都体现价值点。在本例中,用户的价值点除了拥有虚拟货币外,还拥有“票”(具体业务相关,不展开讨论),因此每一个接口或者和价值点有关,或者和待售物品有关
  • 接口应当具有明确的业务意义

接口设计示例如下图所示。


交易系统的外部接口在处了了一些业务逻辑后,最终都将调用核心交易系统的处理过程,这个过程应当遵循如下的3个标准:

  • 初期可以采用“一个一个处理”的串行化方式将涉及到同一个价值点的多个处理过程排队,以保证ACID,例如在Java中可以直接使用Synchronized关键字
  • 每个处理过程应尽量为更多的接口服务,也就是说尽量把外部接口转换成最少的核心交易处理过程
  • 每个处理过程应涉及两个价值点,例如虚拟货币和物品,最多不超过3个

核心交易系统处理过程的序列图示例如下图所示。


在实际的生产环境中,该系统的日最高曾经处理约10万笔交易。当然,这个数值和具体的项目需求密切相关,随着复杂程度的提高,处理能力可能会直线下降,既便如此,也可以满足起步电子商务网站的需求了。从公开的消息可以看到一些参考数据,在2011年11月11日的“双十一”促销期间,京东商城日订单量超过了40万单。

以预订车票为例,核心交易系统要处理的就是身份证、指定日期的指定车次这样一个交易。连钱都不需要处理,因为钱是在预订成功之后支付的。通过本例可以看出,传统的中间件容器方案中,为了避免负荷被中间件容器放大,一般都会仅把核心业务放在中间件容器中,而在自行研发交易中间件时,所有程序按需开发,同时为了应对未来必将出现的需求变更,将一部分需求在交易中间件中实现,也就是模糊了应用和中间件的界限。

发展期核心交易系统程序设计探讨

当电子商务网站继续发展,上面讲到的单机的核心交易系统已经无法满足需求时,就需要进一步提升核心交易系统的处理能力。一般有下面两种策略,一种是资源预分配、另一种是离线锁。

前面提到了资源预分配,也讲到了资源预分配的缺点,但是资源预分配仍是一个非常有效的提升核心交易系统处理能力的方法。以预订车票为例,既然火车的座位数都是可以预知的,那么完全可以预先为每一天的每一个车次的每一个座位准备好空位,就差填写身份证了。如果一台计算机无法处理所有的交易,可以按照每一天的每一个车次来分配在不同的计算机上,这样针对于特定日期特定车次的交易就可以定位在特定的计算机上,而该计算机只需要保证在本机上事务成功提交即可,因为按照业务逻辑,这种预分配资源的方式可以保证计算机之间不会冲突。

针对于春运期间火车票的特殊场境,资源预分配可以进一步优化,比如说对于当天有票释放出的车次,因为访问量巨大,所以尽量拆分开分配分配到独立的计算机上处理,例如每种类型的车次一个计算机集群,对于昨天有票释放出的车次,在春运期间可以认为基本上已经满了,可以把几种类型的车次合并为一个计算机集群,而对于更早释放出的车票,可以认为只剩下退票的情况了,可以把所有类型的车次合并为一个计算机集群,示意图如下所示,当然实际情况要复杂得多。


资源预分配策略可以在一定时期内有效缓解核心交易系统的压力。对于某些负荷变化大的应用,也可以采用资源预分配的策略,例如团购,每一件商品的数量是有限的,很有可能被瞬间抢购一空,此时就应该预先为每一件商品分配空位。类似的,对于秒杀来说,商品数量很少,系统瞬间负荷很大,可以为每一件商品分配一台计算机处理。当然实际情况要复杂得多。

除了资源预分配之外,还有一种处理策略是离线锁,在架构模式中,离线锁包含了乐观离线锁和悲观离线锁两种情况。离线锁设计的初衷是用来解决当客户端长期操作一个数据而锁定数据的时候,服务器端无法同时处理大量的在线锁的场景。在核心交易系统的场景中,一台响应用户请求的计算机替代了客户端的角色,每个需要保证事务的数据(通常是一组数据)对应一个锁记录,在每次请求的过程中,先在锁记录上通过一个原子操作将状态从未锁定状态置为锁定状态,然后操作数据(通常是一组数据),在操作完成后再在锁记录上通过一个原子操作将锁定状态置为未锁定状态。这就是典型悲观离线锁的使用方式。如果把锁记录独立为一个服务的话,就称为锁服务。

在实际场景中,一般是按照资源预分配策略来划分离线锁中锁定的数据粒度,比如说在电子商务网站中,一个用户所持有的所有价值点对应于一个锁,这些价值点包括他的账户、各种优惠券等等,某一个品种的普通商品对应于一个锁,当然也要考虑到前面提到的每一件商品对应于一个锁的情况。而且一般一个事务会锁定二个到三个数据,例如在一次消费过程中,先锁定用户,锁定商品,然后操作用户、操作商品,最后释放用户锁、释放商品锁。如果在操作过程中发现异常,则在释放锁之前恢复数据,保证一致性。

“海量事务高速处理”期核心交易系统分析探讨

当系统演讲到海量事务高速处理阶段,如前面所述,整个交易系统是完全按照需求定制的,下面仅就一些共性的问题做简要的探讨。主要涉及三方面的问题,系统的可用性,锁的粒度,以及事务的划分。

首先看系统的可用性,任何系统随着规模的增长,设备故障的频率也将越来越高,此时就需要有相应的容灾策略。需要消除单点、甚至于单集群故障。在前面提到的锁服务也就不能采用通用的数据库来设计。目前流行的做法是采用基于Paxos算法的锁服务,通过五台计算机(最少是三台,一般是奇数个,考虑容灾的需要一般用五台,更多的计算机会造成之间通讯量的快速增长)组成一个针对某类资源的锁服务集群。在操作某一项资源时,先在锁服务上对这一项加锁,操作之后解锁。这和悲观离线锁机制相同,当然在实际操作中,因为还要消除保存资源数据的计算机的单点故障,加锁和解锁的过程要和所有数据的一致性保持同步。

既然锁是以锁服务的形式存在,那么如何划分锁的粒度就成为效率的关键,锁的粒度太细的话,一个事务中操作锁的次数就太多了,锁的粒度太粗的话,碰撞的可能性就大得多。另外,既然锁已经独立于数据,因此一组锁服务可以为几类数据量不大的数据服务,对于数据量很大的数据可以分成几组锁服务。

锁的粒度划分又和事务紧密联系在一起,一般来说,一个事务中持有的锁越多,碰撞的机会就越多,而碰撞的结果就是回滚。从定性的分析来看,可以用N^2来评价,比如说一个事务中持有两个锁,那么碰撞的机会就是4,持有三个锁的话,碰撞的机会就是9。也就是说,如果把一个需要持有三个锁的事务划分成两个持有两个锁的阶段的话,碰撞的机会就是2*4=8<9。从这个简单的定性分析可以看出,事务应以2个锁为主,不超过3个锁。4个锁以上的事务一定要分解成多个小事务。当然经过分解之后,复杂程度也随之提升,但是因为减少了碰撞,系统的总体性能获得了提升。也就在另外的一些环节中减少了系统的复杂度。

系统的可用性、锁的粒度以及事务的划分这三个问题既相互独立,又相互联系。对于核心交易系统来说,合理的事务划分可以提升性能,从而减少计算机的数量,间接提升了可用性。

另外一些误区

在前面提到了采用类似于EJB的中间件容器或者将事务交给数据库处理是两个主要的误区,下面谈一谈其他一些认识上的误区。

加强CDN建设能提升核心交易系统性能。答案是没有直接联系,对于电子商务网站来说,CDN的价植更多体现在CMS产品上,也就是货架陈列产品上,对于涉及到事务的MIS、OA、ERP来说,不可能使用CDN的缓存,最多使用CDN的路由加速功能。这些对于核心交易系统没有直接联系。

将核心交易系统建设成开放平台有助于简化核心交易系统,提升交易性能。答案正好相反。内部系统纵然有种种弊端,但是对于任何一个细节都是可控的,而对于开放平台来说,难以控制外部的操作,为了应外可能出现的负荷变化可能要做更多的准备。换句说话,在内部系统还没有完善的时候,开放平台不仅没有帮助,反而可能放大现在的缺陷引发连锁崩溃。

对于其他的误区欢迎各位联系,我将继续补充。

作者简介

作者胡争辉,CSDN博客专家,CTO俱乐部成员。曾任完美时空(现更名为完美世界)顾问,承担互联网方面的部分管理工作。现在主要精力研究互联网产品设计,是Axure授权的高级咨询顾问和高级培训讲师。

个人博客:http://blog.csdn.net/hu_zhenghui

 

个人网站: http://bbs.hpx-party.org/

 

个人邮箱:hu@hpx-party.org  huzhenghui@139.com

 

新浪微博:@胡争辉

 

QQ:443089607

 

GMail& GTalk: huzhengh@gmail.com

 

Fetion:293089651

 

声明

本文不是专业的学术论文,重点为介绍相关背景知识,写作过程有失严谨之处敬请同行斧正。如果各位觉得有必要继续深入探讨,我将继续写点东西和各位探讨财务系统的分析设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_899914.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

很好用的壁纸网站源码分享,仅供学习,请勿商用。

分享一个壁纸网站源码&#xff0c;无需安装&#xff0c;修改之后就可很好使用。 集合360壁纸&#xff0c;百度壁纸&#xff0c;必应壁纸&#xff0c;简单好用。 演示地址&#xff1a;http://www.toqia.com/bizhi/ 好用的话&#xff0c;记得点赞哦。 百度网盘&#xff1a;链…

每天访问量至少达100万的29个社交网站

尽管Facebook目前是第一大社交网站&#xff0c;但是在社会化网络领域里面的其他网站同样也不可小觑。为了一窥各个知名社交站点的活跃状况&#xff0c;我们采用Google Trends对一些主流的社交站点进行了流量分析&#xff0c;并列出29个每天独立访问量达到100万的网站。虽然独立…

浏览量比较大的网站应该从哪几个方面入手

作者: 游戏人间 时间: 2007-6-15 04:23 PM 标题: 浏览量比较大的网站应该从哪几个方面入手&#xff1f;当然&#xff0c;提问前先将个人的一些理解分享。大家有的也请不吝共享&#xff0c;偶急切的需要这方面的经验....下面所提到的主要是针对一般的网站&#xff0c;不包…

高负载、高并发网站架构知识汇总-大型互联网网站架构

我们知道&#xff0c;对于一个大型网站来说&#xff0c;可伸缩性是非常重要的&#xff0c;怎么样在纵向和横向有良好的可伸缩性&#xff0c;就需要在做架构设计的时候考虑到一个分的原则&#xff0c;我想在多个方面说一下怎么分&#xff1a; 首先是横向的分&#xff1a;1. 大…

使用 PHP 搭建自己的视频点播网站,第 1 部分:基础工作

现在注册或者使用您的 IBM ID 和密码登录。 搭 建您自己的视频点播网站并不复杂。上传一些视频&#xff0c;然后供人们观看。就这么简单。但是如果您想要做很多视频&#xff0c;则必须将它们组织起来。这个 “使用 PHP 创建自己的视频点播网站” 教程系列包括三部分&#xff0…

Linux建立网站LAMP Aache

概念 firewalld 简介&#xff1a; 保护互联网对服务器的影响cat selinux简介&#xff1a; 保护服务器内部程序(ftp)对内部文件(/var/ftp)的访问 firewalld 临时关闭 : systemctl stop firewalld firewalld 状态查看方法&#xff1a;systtemctl status firewalld firewalld…

Linux 域名服务及阿里云搭建网站

概念理论 搭建阿里云服务器 DNS 解析

理论+实验:LAMP网站服务器部署(超详细版本)

目录 一、 LAMP介绍二、Apache 简介三、Apache 的主要特点四、搭建YUM仓库五、编译安装HTTP服务六、站点部署6.1 基于域名主机的6.2 基于IP地址的6.3 基于端口的 七、安装mysql八、安装PHP环境九、安装phpMyadmin 一、 LAMP介绍 LAMP 架构是目前成熟的企业网站应用模式之一&…

为SharePoint网站创建自定义导航菜单

相信不少人都希望把SharePoint网站内置的那个顶部导航菜单&#xff0c;换成自己希望的样式。由于SharePoint 2007/2010的网站导航基本上基于标准的ASP.NET SiteMap模型&#xff0c;所以只要你对ASP.NET SiteMap有一些了解&#xff0c;就能创建一个自定义的导航菜单。 在开始之…

Hexo+Github/Gitee搭建静态网站博客

前言 Hexo是一个快速&#xff0c;简单&#xff0c;功能强大的开源博客框架。 GitHub/Gitee Pages 是一个国内外静态资源网站。 两者结合可以搭建用户自己的静态网站。 搭建hexo 安装node.js 根据操作系统&#xff0c;在官网下载对应的安装包&#xff0c;地址为:node.js。 下…

响应式Web设计帮助移动终端访问网站

2012年被称为智能手机年。根据最近一份调查显示&#xff0c;美国的智能手机覆盖率已达50%。现在确实是提升移动终端用户体验的大好时机。如果你正运营一个网站&#xff0c;那就必须有一个响应式的Web设计&#xff0c;以便可以从移动终端上很好地访问你的网站。如果你还没意识到…

循序渐进BootstrapVue,开发公司门户网站(6)--- 门户网站后端内容管理

我们在做门户网站的时候&#xff0c;如果网站的内容可以动态从后端进行管理&#xff0c;那么调整网站内容就非常方便&#xff0c;有时候如一些公司新闻、产品信息、轮播广告信息等都需要动态调整的&#xff0c;有一个方便的后端内容管理是非常方便的。本篇随笔介绍门户网站的后…

python3.6爬虫案例:爬取某网站所有PPT(上)。

写在前面 这次实现之前的flag&#xff1a;爬取第一ppt网站的所有PPT&#xff0c;当然网站中有其他很多的学习资料&#xff0c;这次只爬取PPT。不仅可以平时做模板演示用&#xff0c;还可以练习爬虫&#xff0c;岂不美滋滋。闲话不多说&#xff0c;进入正题。 先来说下网站&am…

python3.6爬虫案例:爬取某网站所有PPT(下)。

上篇博客&#xff1a;python3.6爬虫案例&#xff1a;爬取某网站所有PPT&#xff08;上&#xff09;给大家介绍了爬取&#xff08;http://www.1ppt.com/&#xff09;网站中的ppt文件&#xff0c;爬下来的文件如下&#xff1a; 所以&#xff0c;我们就要考虑将其名称修改为其在网…

利用Python爬取妙笔阁小说网站的小说信息并保存为txt和csv格式

本次爬取的是妙笔阁小说网仙侠系列中所有小说的信息&#xff0c;打开网页会看到如下图所示的小说列表。 根据列表&#xff0c;选择爬取小说的书名、作者、最新更新、简介这四项信息。 在爬取之前&#xff0c;为了防止网站禁止爬取&#xff0c;需构造访问的请求头&#xff0…

仿360网站广告实现换肤特效

1、新建一个web项目&#xff0c;index.jsp同级目录下放jquery插件和top_right.png图片 2、index.jsp页面代码 <% page language"java" import"java.util.*" pageEncoding"utf-8"%> <% String path request.getContextPath(); String b…

仿360小说网站的源码设计实现

360首页检索小说效果如下&#xff1a; 个人完成编写的schoolnet校园网主页如下 在小说模块中&#xff0c;包括&#xff1a;小说类别编号&#xff1a;a、校园爱情 b、动漫同人 c、校园魔法 d、轻小说 e、校园励志 f、校园修真 g、名人传记 h、古典小说 …

基于仿360小说网站(校园网)的源码设计实现(升级版)

基于博文仿360小说网站的源码设计实现对小说网站的源码更新升级&#xff08;动漫小说网&#xff09;。 网站PC电脑端效果截图&#xff1a; APP手机端效果截图&#xff1a; 数据库相关表设计&#xff1a; 主要包含小说id,章节id,类型ID,小说名称,章节名称,作者,缩略图,图片地址…

动漫网站源码设计与实现

已完成编写的Sky动漫网主页如下 PC电脑端效果截图&#xff1a; APP手机端效果截图&#xff1a; 数据库相关表设计如下&#xff1a; 主要有&#xff1a;动漫主体信息表、视频播放源表、文章资讯表、主题专辑表、经典语录表、图片图集表、评论表等等 信息采集使用jsoup爬取 各…

第二次作业------仿制网站

码云链接&#xff1a;https://gitee.com/eiumc123/12.git 百度云链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1ej-JvlRfRYe8KzGje-ULOQ 提取码&#xff1a;fnmv &#xff08;文件中有视频&#xff0c;过大无法上传到码云&#xff0c;所以。。。&#xff09; <…