如何设计一套秒杀系统

1. 如果项目组中使用的redis是单机版的,如何处理QPS在10万+的场景?

首先讨论这个问题的前提是java应用层的性能要大于redis性能,不然请求无法到达redis。那假如当前QPS是15万+,redis可以处理10万,那么另外5万,何应用可以处理呢?

方案1:

java本地缓存,我们还需在思考一个问题,何种数据存java本地缓存,何种数据存redis?这就需要根据缓存的特性进行分析。

当前的java应用都是集群式,分布式的应用,那么本地缓存也将是多份的。除此之外,java本地缓存相对redis缓存来说是更为有限的。所以,java本地缓存适合存放一些静态的,占用空间不大的,访问量大的数据。Redis作为集中式缓存可以存放会动态变化的,占用空间相对较多的数据。

方案2:

redis读写分离,redis主机复制处理写请求和同步数据给从机,redis从机负责处理读请求,假设从机使用其50%的性能,每个从机每秒处理5万的请求,构建3台从机即可。

2. 单条数据的高并发场景,如何在应用层进行排队?

可以设计一个线程池,处理高并发场景下的写请求

3.  淘宝系统设计秒杀系统的思路

淘宝系统的秒杀方案,主要基于下面2个方面去考虑:热点隔离,数据分层校验

热点隔离的出发点是不想让1%的请求影响到99%的请求,而隔离方案的实施可以从下面3个方面进行处理:

业务隔离: 秒杀时,参与活动的产品和商家可以提前知道,对于这些数据可以提前做好预热。

系统隔离:独立系统处理秒杀请求。

数据隔离:独立的缓存系统和数据库系统,存放热点数据。

数据分层校验:思想如果数据可以满足用户的需求,就不用将请求向下传递

前端缓存,对于静态信息,前端可以进行缓存处理。

动静分离,出发点是要尽可能的将静态资源放到客户端或者CDN, 对静态资源的请求不用到达应用端。

基于时间分片削峰,前端增加个答题功能,用户在下单时需要完成个答题任务,才能下单,使下单流程变长,由之前的1秒内变到2~10秒,并且起到了防止秒杀器的作用。

服务端缓存应用本地缓存和缓存中间件的集中式缓存

单一商品高并发读问题,秒杀时商品的信息定然会放在缓存当中,如果使用的是redis集群,那么单个商品必然存在redis集群中的某个节点上,缓存节点的性能将成为系统的瓶颈。这个问题可以从两个方面来解决,1是将单个商品的信息分为静态信息和动态信息,静态信息放本地缓存,动态信息放redis缓存;2. redis 集群做读写分离,通过扩张从机来提高集群的请求处理能力。

单一商品高并发更新问题,单一商品高并发会引发什么问题呢?一个数据库线程更新某条记录的时候,其他的线程都要处于等待当中,这样的等待占用的数据库的线程和连接数,也占应用的线程数,这样的话应用将无法处理其他请求,如果不做隔离处理的话,还会影响到连接该数据库的其他请求,使得功能大面积瘫痪。解决方案:下单请求异步返回减少用户等待,在应用层进行排队处理(可以考虑使用线程池来处理下单任务)这样可降低数据层面的高并发,减少数据库的压力

需关注问题:是否有新的热点数据生成,如果有,也需要进行上面的处理

 

 

java实现秒杀系统@Controller @RequestMapping("seckill")//url:/模块/资源/{id}/细分 /seckill/list public class SeckillController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private SeckillService seckillService; @RequestMapping(value="/list",method = RequestMethod.GET) public String list(Model model){ //获取列表页 List list=seckillService.getSeckillList(); model.addAttribute("list",list); //list.jsp+model = ModelAndView return "list";//WEB-INF/jsp/"list".jsp } @RequestMapping(value = "/{seckillId}/detail",method = RequestMethod.GET) public String detail(@PathVariable("seckillId") Long seckillId, Model model){ if (seckillId == null){ return "redirect:/seckill/list"; } Seckill seckill = seckillService.getById(seckillId); if (seckill == null){ return "forward:/seckill/list"; } model.addAttribute("seckill",seckill); return "detail"; } //ajax json @RequestMapping(value = "/{seckillId}/exposer", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"}) @ResponseBody public SeckillResult exposer(@PathVariable("seckillId") Long seckillId){ SeckillResult result; try { Exposer exposer =seckillService.exportSeckillUrl(seckillId); result = new SeckillResult(true,exposer); } catch (Exception e) { logger.error(e.getMessage(),e); result = new SeckillResult(false,e.getMessage()); } return result; } @RequestMapping(value = "/{seckillId}/{md5}/execution", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"} ) @ResponseBody public SeckillResult execute(@PathVariable("seckillId")Long seckillId,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值