Java Web高并发抢单如何实现?

     首先第一步,你得让海量请求进来,第二步才是对进来的请求排队处理。第二步只是时间问题,要么像kafka那样,要么像redis那样。第一步单机一定会遇到瓶颈,无论集群还是分布式,跨机器的处理都会多出io时间,vertx是怎么 让多服务器同时处理还省去io时间的?这不科学吧?就算vertx单台服务器可以处理很高很高的并发,也不可避免要用集群,因为要保障的事高可用,而不只是高并发,跨服务器数据处理不可避免。

     你的spring MVC是处理请求的,截取到request以后,先解析,然后生成message。接下来你需要一个q,你有两个选择,spring integration去连普通的queue,比如开源的activeMQ,或者用spring amqp,像这个官网例子Spring AMQP,从q里面取,当然是反向的,你选好了怎么放,就对应的怎么取。这是简单层面的,商用化的话,你还要考虑一致性,错误处理等,我感觉你是在练习,这些先别增加复杂度了。这个message加入队列,着一个架构动作,和数据持久层并没有关系。数据持久层应该是在两部做动作,1,是加入q处理之前,你可能想永久化一下,2,是处理成message了,后台进行业务处理,那么业务动作结果肯定要存在持久层里面。

Java Web高并发抢单如何实现?_第1张图片
 

       秒杀这个功能,往简单的说就是一个资源争夺的典型例子。一些书里经常会用多终端共享打印机来说明这种独占资源共享的场景。解决资源抢占冲突的手段往往就两个,减少冲突方或增加资源。
秒杀需要占用的最重要资源是库存计数,其次是执行时间。抓住这个关键点就好办了,用什么框架什么技术,无非也就是保证这个计数不被脏读脏写,同时保障其他流程快速稳定地运行至结束。

那么最简单的思路,就是将请求排队,再慢慢消化这些。也就是说,虽然很多订单请求过来,但是真正处理订单的处理程序就一个,所有请求被队列hold住后由单一程序处理,这样直接避免了脏读脏写问题。这种方案用得最多的就是下边很多答主提到的消息中间件。
但这样的方案是以降低吞吐量为代价的,毕竟仅安排一道程序处理队列,队列平均等待时间会非常长。
这种设计通常用户会感觉秒杀后系统相当长时间失去相应。

进阶的做法就是想办法快速消耗队列,比如不再使用单线程处理队列,转为仅使用队列进行任务调度,并由调度程序控制库存计数,订单后续操作分派到其他线程甚至其他服务完成。这样,库存计数仍然由单线程顺序操作,可以避免脏读脏写问题,同时调度线程可以迅速消耗队列,队列平均等待时间可以进一步缩短。
这样的秒杀模型就变成了一个,预先占有资源后并发处理后续流程的模型。如果抢占不到资源,调度器自然会将请求交由错误处理程序处理。
队列平均等待时间减少带来最直观的感受,就是用户觉得秒杀结果出来更快。

以上两种方案,是以保护共享资源为出发点做文章,为了保护共享资源,不可避免的选择降低资源访问频率来降低冲突可能性,从而影响程序速度和用户体验。
另一种思路是增加资源,从而进一步降低资源争夺的可能。
其中一种较为广泛的技术是多级缓存机制,其根本原理是将单一的库存计数以更细粒度拆分。这样可抢夺资源变多,资源争夺的概率就会降低。同时,这种设计还可以进一步横向扩展,充分利用集群优势。

更复杂的还有以单元架构为基础,结合以上多种手段,从每年天猫双十一后公开的文档看,几乎能扛住所有秒杀流量了。

想清楚了这些手段,用的什么框架,什么存储方案,几乎都能建立起一套轻松抗百万并发的系统,并不是其他回答所说的,框架不优秀导致,更不是简单一句优化就可以做到的。

建议题主仔细分析自己的业务需要多高的复杂度,需要多复杂的实现,秉承够用就好的选择,选择最佳方案。

你可能感兴趣的:(互联网)