高并发事务处理方案 秒杀的分析

      前端时间被人问到一个问题:抢购(秒杀)系统的搭建。不清楚这个面试官为什么问这个问题,但我觉得我当时的回答还是在点上的,只是措手不及逻辑不清楚而已。现在把思路落地。
    我们要明白秒杀系统的难点:高并发  事务控制  快速响应。
    大数据量的处理,难点就是在事务处理和复杂计算上。为了提高系统的响应速度,就要采用集群+多线程的处理方式。而数据库显然就成了整个系统的瓶颈,数据库集群方案涉及的方方面面实在太多太多,尤其是事务处理上(互联网企业涉及的复杂计算不多)。前台再多的集群,再多的线程,到了事务层面都要变成串行。因此,现在的互联网企业都采用“数据无状态”加“回滚段”来弱化事务处理。而秒杀显然不能这样处理,用户抢商品时,后台需要先查询、再更新。从事务的分析上来说就需要加行级查询锁。如果不加锁机制,估计项目经理第二天就得被辞退,还得搭上自己好几年的薪资。用回滚段,就要被客服和客户骂死了。所以说嘛,还得是事务处理,回滚段只能保证数据的完整性,却保证不了数据的正确性。
    再说说高并发的处理,这个应该就是运维方面的事情了,软件层面没有什么好的方案。据我所知,无论是linux还是windows都有双机热备的处理方案,进而扩展为集群部署、负载均衡方案等等(其实,我一直觉得这方面的处理从路由器来解决比较合适,想不明白为什么会在操作系统层面处理,服务映射到一台服务器了,再要飘移到其他的服务器,有种多此一举的感觉)。应用层面采用nginx+tomcat集群部署,就能应付高并发(恶意攻击.......)。再多的问题超出我能力范围了.......
    下面从软件编程的方面来解决秒杀的事务控制。上面讲了,秒杀的事务控制是在行级别的,也就是查询时锁定一行记录。所以嘛,用现在的经典说法,就是事务拆分。大事务拆分成小事务,也就是一行记录拆成多行记录(甚至是拆分到多个数据库,也不知道“事务拆分”是不是这么理解的?),每行记录单独加锁。这样就可以支撑数据库层面的多线程并发处理了。
    既然拆了多个数据库,就不能采用一个应用绑定一个数据库的方式来处理。软件编程的基本规则嘛。于是就得设计个后台的抢客机制,webservice或者activemq登场了。我当时的回答是用activemq,当时是想让后台的线程来抢客户,而不是让中间件来轮询,而且activemq是支持消息持久化的(估计早期的12306排队机制就是采用这个方式处理的),也就是说,系统记录了你的操作,但是并没有进入持久化层面,目的是提高前台的响应效率。但是我忽略一个重要的问题,那就是抢购的即时效应(需要立即反馈,其实activemq是支持即时消息机制的,怪我当时没说这句话,唉。没有时间研究mq即时机制和webservice有什么区别,在实现技术上和广播订阅方式的消息机制有没有区别)。这样,webservice就是很好的解决方案。
    ok,目前看所有的问题都解决了,只要服务器足够多。
    下面再说一下我的优化方案,我们都清楚,专卖店的商品都会放到两个地方,仓库和柜台。仓库,我们可以理解为数据库、柜台呢,当然是内存了。没错,加入内存缓存框架,减少读写数据库的操作。
    接着优化,抢购嘛。就是单一商品了,没得挑,没得选。既然没得选,后台线程你就直接拿了货在门口等着好了。来一个给一个,简单明了。抽象到代码,就是做一个线程池,到点前,初始化线程池,池里的每个服务员每人拿一个商品,客户来了,主线程从线程池里取线程,有就返回,抢购成功,并唤醒当前线程去登记出货信息并从仓库里从新拿货排队,如果没有线程等待就是没有抢到。这样,连调用缓存接口拿货的等待时间都省了。
     再优化一下,上面的方案有个漏洞。就是退货,因此还得加一个监听线程,负责监听缓存池的资源直到本次抢购完成才能回收。这个线程也可以负责线程池的初始化,这样逻辑就更清晰漂亮了。 

猜你喜欢

转载自blog.csdn.net/sjc106112/article/details/47733631