Java开发面试:高并发秒杀系统如何设计与优化

2024-06-21 21:18

本文主要是介绍Java开发面试:高并发秒杀系统如何设计与优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载链接
如今处在一个大数据时代,应届生找工作面试高级Java开发工程师时,经常会被问一些和大数据相关的问题,比如大数据处理问题、高并发处理问题、数据优化问题等,笔者曾经遇到两个比较经典的问题,高并发秒杀系统的设计优化问题和大数据文件排序问题。在这里总结了高并发秒杀系统的设计和优化点。

面试官常问的问题有:

简单说一下秒杀系统的设计思路?

你怎么实现秒杀业务的?

你怎么保证秒杀成功的?

秒杀操作的策略是什么?

你使用的Redis有什么用?

你为什么使用Redis中间件?

你测试过你这个系统的抗压能力么?

你使用过什么方法来测试你的系统并发量?

你觉得你这个系统还可以再优化么?

你觉得你这个系统的瓶颈在哪里?还可以在哪些方向做进一步优化?

  很多面试官问的比较笼统,很少面试官问的比较具体,事先的这些问题,都要做好准备,笔者的准备思路是:功能模块划分=》秒杀策略=》自己的优化点=》工具测试抗压=》别人提供的优化方法和秒杀策略

1 秒杀系统特点
秒杀业务简单,卖家查询,买家下订单减库存。
秒杀时网站访问流量激增,出现峰值;
访问请求数量远大于实际需求量。
2 架构设计优化方案
1 秒杀系统架构设计优化
一个常规的秒杀系统从前到后,依次有:

              前端浏览器秒杀页面=》中间代理服务=》后端服务层=》数据库层根据这个流程,一般优化设计思路:将请求拦截在系统上游,降低下游压力。在一个并发量大,实际需求小的系统中,应当尽量在前端拦截无效流量,降低下游服务器和数据库的压力,不然很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。 

整体设计思路和优化点:

限流:屏蔽掉无用的流量,允许少部分流量流向后端。

削峰:瞬时大流量峰值容易压垮系统,解决这个问题是重中之重。常用的消峰方法有异步处理、缓存和消息中间件等技术。

异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。

内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。

可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。

消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。

充分利用缓存:利用缓存可极大提高系统读写速度。

2详细方案

2.1 前端方案
静态资源缓存:将活动页面上的所有可以静态的元素全部静态化,尽量减少动态元素;通过CDN缓存静态资源,来抗峰值。
禁止重复提交:用户提交之后按钮置灰,禁止重复提交
用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流

2.2 中间代理层
可利用负载均衡(例如反响代理Nginx等)使用多个服务器并发处理请求,减小服务器压力。

2.3 后端方案
控制层(网关层)

        限制同一UserID访问频率:尽量拦截浏览器请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。

服务层

当用户量非常大的时候,拦截流量后的请求访问量还是非常大,此时仍需进一步优化。

1.业务分离:将秒杀业务系统和其他业务分离,单独放在高配服务器上,可以集中资源对访问请求抗压。

2.采用消息队列缓存请求:将大流量请求写到消息队列缓存,利用服务器根据自己的处理能力主动到消息缓存队列中抓取任务处理请求,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。

3.利用缓存应对读请求:对于读多写少业务,大部分请求是查询请求,所以可以读写分离,利用缓存分担数据库压力。

4.利用缓存应对写请求:缓存也是可以应对写请求的,可把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。

2.4 数据库层
数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。

   如果不使用缓存来作为中间缓冲而是直接访问数据库的话,可以对数据库进行优化,减少数据库压力。对于秒杀系统,直接访问数据库的话,存在一个【事务竞争优化】问题,可使用存储过程(或者触发器)等技术绑定操作,整个事务在MySQL端完成,把整个热点执行放在一个过程当中一次性完成,可以屏蔽掉网络延迟时间,减少行级锁持有时间,提高事务并发访问速度。

2.5 其他秒杀策略
减少硬件开销的策略 :

   策略1:消息队列缓存请求,按照队列模型取任务执行,秒杀完毕即终止到秒杀结束页面。策略2:使用数组为并发请求随机分配秒杀状态(成功和失败),然后将分配到失败状态的请求派发到秒杀失败的页面,分到成功状态的用户在慢慢的按顺序执行秒杀操作;(如果处理失败了可以利用日志来查找具体秒杀失败的商品和用户,执行补救措施或者从其他用户中拿取一个来执行秒杀操作)策略3:类似于策略2,不过是用数组为用户分配秒杀资格,将大流量的用户限制为小流量的用户,得到秒杀资格的去执行秒杀,得不到秒杀资格的跳到秒杀失败页面。 

(分配状态或分配秒杀资格的策略:(数组状态密度不同,由前到后逐渐稀疏,可以让先到的在前面随机分配,后到的在后面随机分配)根据先到的时间)

3 案例:利用消息中间件和Redis缓存实现
Redis是一个分布式缓存系统,支持多种数据结构,可利用Redis轻松实现一个强大的秒杀系统。

   我们可以采用Redis 最简单的key-value数据结构,用一个原子类型的变量值(AtomicInteger)作为key,把用户id作为value,库存数量便是原子变量的最大值。对于每个用户的秒杀,我们使用 RPUSH key value插入秒杀请求, 当插入的秒杀请求数达到上限时,停止所有后续插入。然后我们可以再启动多个工作线程,使用 LPOP key 读取秒杀成功者的用户id,然后再操作数据库做最终的下订单减库存操作。当然,上面Redis也可以替换成消息中间件如ActiveMQ、RabbitMQ等,也可以将缓存和消息中间件 组合起来,缓存系统负责接收记录用户请求,消息中间件负责将缓存中的请求同步到数据库。

(1)使用Redis中间件缓存动态资源的好处?

   提高访问速度,减少对数据库的链接的打开、关闭,

(2)为什么不用JVM内存而使用Redis作为缓存呢?

  JVM 内存较小,隔一段时间会自动进行垃圾回收。JVM和业务程序绑定在一起了,如果程序出错,JVM也会停止,这样就导致缓存数据丢失。如果使用Redis,除了缓存比较大之外,还实现了缓存数据和业务程序的分离,即使运行程序出现错误,也不会影响缓存。

3 压力测试
使用JMeter 压测工具

下载、安装、进入C:/JMeter/bin下面的jmeter.bat批处理文件来启动JMeter的可视化界面,

进入测试计划添加线程组: 设置线程数,循环次数,添加HTTP默认请求,服务器名称,IP,以及自己设定的携带参数

添加监听器,存放测试结果:聚合报告,可以表格查询、图形结果、树结果

点击运行-》启动。

并发量:50W-100W 100W-500W

这篇关于Java开发面试:高并发秒杀系统如何设计与优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1082360

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input