【springboot项目】之秒杀项目常见问题(Seckill)

秒杀问题分为两部分:用户查看商品详情页、用户下单

项目简介:

模拟了高并发场景的商城系统,它具备秒杀功能,为了解决秒杀场景下的高并发问题。引入了 redis 作为缓存中间件,1.主要作用是缓存预热、预减库存等等。2.针对高并发场景进行了页面优化,缓存页面至浏览器,前后端分离降低服务器压力,加快用户访问速度。

先不答:在安全性问题上,我使用双重MD5密码校验,隐藏了秒杀接口地址,设置了接口限流防刷。

最后还使用数学公式验证码不仅可以防恶意刷访问,还起到了削峰的作用。通过 Jmeter 压力 测试 ,系统的QPS从150/s提升到2000/s。

QPS:【Queries-per-second】每秒处理事务数(每秒查询率)

一、查看商品详情页

1.初始化流程图

介绍:若redis中有数据就把数据返回到前端,若没有数据则请求数据库;

一条查询操作,在service层首先走Redis,若命中直接返回,否则去底层数据库中查,查询到了,返回给service层,并将查询结果保存在redis中,后返回给Controller

问:有无更快一点的方法?

利用多级缓存:查询redis会有网络请求,所以会产生一些i/o带宽的浪费,所以可以考虑把热点数据存储到jvm内存中去(热点数据:基本不变的数据),此时前端请求直接走jvm,没有一些I/O读写的操作,所以速度就会变快一些;若jvm内存中没有数据,再去redis中去查,redis中没有再去数据库查。

注意:但是jvm的内存是非常宝贵的,所以我们只存放非常热点的数据,不经常容易变的数据;
问:jvm并发有限,比如要抗住10万并发量怎么办?

答:1 .利用服务器集群,比如我们一个机器可以抗住1w并发,那么我就可以利用10个机器去解决10万并发的问题;用Nginx来做负载均衡:用上一些轮询算法等(左图所示);**2.**还可以利用缓存来解决,我们把这个缓存放在距离用户最近的地方(这样子系统就会很快,用户体验也会很好),从目前这个流程图看,Nginx是距离用户最近的地方,所以我们可以用Nginx去访问这个redis(下两个图所示)

关于优化的问题

问:如商品详情页会有很多静态资源,这些静态资源怎么处理?

答:商品详情页有很多静态资源:比如我们写好的css,jss,html等,若去服务器上请求会浪费性能,这个时候我们可以把这个静态资源缓存到这个CDN上面,然后浏览器就可以直接去CDN上取这个静态资源,此时速度就会提升很多;

关于CDN:cdn优化的是用户访问静态资源的速度;
问:但是页面上显示的数据还得去后端接口查询出来,而我又不想去后端接口查询数据,如何处理?

答:在后端把页面完全静态化,然后把整个这个静态化好的资源放到CDN上面去,浏览器直接请求CDN上的详情页就可以直接显示了;

再问:那什么是页面静态化呢?

答:后端数据实时得渲染到前端页面上,才能显示不同的页面数据;因为有些商品详情的信息是基本不会发生改变的,页面静态化就是提前把这个数据渲染到页面上,然后把页面提供给用户访问。

二、秒杀下单

在活动开始之前,提前先把这个商品的库存缓存到redis中去,在redis里面进行一个预减库存的操作。(因为高并发下修改数据库的数据,会引发锁竞争);这样的话就不用频繁的去修改数据库中的数据,也就有效减少了锁竞争的问题

问:接上:那你是如何保证这个redis和数据库的数据一致性呢?

答:我们在redis和数据库之间加上MQ,用mq异步的方式同步这个信息。也就是说:扣减库存的操作在redis里面执行,然后把扣减库存的信息告诉MQ,然后MQ再通知MySQL扣减了多少库存;

队列排队下单

问:两个小问题
①mysql消费mq失败怎么办?②在数据库中创建订单失败了怎么办?

答:我们可以利用分布式事务来解决一下,如MQ中的rocket mq去解决;(因为rockt mq对事务比较友好)

问:那么不用mq,且redis挂了怎么办?

答:----(暂未写好答案)

问:一千万人秒杀商品,但是库存只有100w件怎么办?其余的人还在不断地请求我们的系统,这样子好吗?
做了什么流量削峰的措施?秒杀令牌

答:首先这样子肯定不好,一个是对系统的性能有影响,再一个就是用户的体验性不好;

如何解决:我么可以添加一个秒杀令牌的概念,但凡是想要参加这个秒杀活动的用户,必须先获得这个秒杀令牌(类似于活动入场券,有了入场券才能参加活动),我们在用户进行秒杀之前先判断他有无这个令牌,有令牌的则让进来进行秒杀;并且这个令牌的数量是有限的,当我们令牌发放完毕,我们就不让其他用户在继续请求我们的后端接口,直接拒绝用户的请求,减少系统资源的消耗和压力;

我们可以设置为库存量的5倍,500w个令牌;也就是说500万用户来抢夺这个100w件商品;我们不能把令牌的数量设置=库存数量,是因为有很多用户抢到了商品,但是最后还是没有付款,所以设置的多一些,可以让其他想要买的用户去抢;

还可以作为优化的地方:

1.限流操作

同时因为我们秒杀的商品种类不止一件,所以我们虽然设置了令牌机制,但是我们的秒杀流量依然很大,所以我们要进行一些限流的操作,如下图,我们在后端接口上用jmeter做后端系统的压测;比如我们这个秒杀的接口最多只能承受1w的并发,我们就要限流,比如限流8000,限流的好处就是防止系统被压垮,使得系统可以继续对外提供服务;

2.队列泄洪

接口里面进行一个队列泄洪操作;

因为在我们的接口里,会有大量的线程进来,去竞争创建订单,也就是说同时竞争这个cpu资源;而Redis是单线程的(redis是单线程的,是非常快的,因为没有cpu的上下文切换和i/o的多路复用);假使我们的cpu同时只能处理100个请求,而此时已经进来10000个线程来竞争cpu,此时的话会产生很多的性能消耗;

所以我们可以考虑把这10000个线程放在一个队列里面,然后让cpu从队列里面进行消费线程,一次只拿100个,执行完以后再从队列里面取100个,这样子cpu能处理的线程数和我们提供的线程数相等,此时就不会产生一个竞争问题。

3.熔断机制

利用熔断降级的逻辑保护系统,防止意外的大量的请求压垮系统,从而造成整个系统的瘫痪;

具体介绍:当出现系统无法承受的流量时候,我们利用熔断暂时先把请求全部拒绝,等到系统慢慢恢复再重新打开;

当熔断出现后,我们拒绝其他的请求,只剩下一小部分请求过来,看系统是否可以响应,等到系统恢复完全,我们再把接口全部开放;

同时配合这个降级的逻辑,也就是说,拒绝用户请求的同时返回一个友好提示:如,系统繁忙,请稍后再试

4.再者我们进行分布式服务,把服务横向扩展,让更多的独立的服务器去扛这个高并发
相关推荐
zwhdlb4 分钟前
Java + 工业物联网 / 智慧楼宇 面试问答模板
java·物联网·面试
Pitayafruit6 分钟前
Spring AI 进阶之路04:集成 SearXNG 实现联网搜索
spring boot·后端·ai编程
风象南8 分钟前
SpringBoot 自研「轻量级 API 防火墙」:单机内嵌,支持在线配置
后端
码熔burning20 分钟前
JVM 面试精选 20 题(续)
jvm·面试·职场和发展
刘一说20 分钟前
CentOS 系统 Java 开发测试环境搭建手册
java·linux·运维·服务器·centos
Victor35625 分钟前
Redis(14)Redis的列表(List)类型有哪些常用命令?
后端
Victor35626 分钟前
Redis(15)Redis的集合(Set)类型有哪些常用命令?
后端
卷福同学27 分钟前
来上海三个月,我在马路边上遇到了阿里前同事...
java·后端
bingbingyihao2 小时前
多数据源 Demo
java·springboot
Monly215 小时前
RabbitMQ:数据隔离
分布式·rabbitmq