当前位置: 首页 > news >正文

【代码笔记】高并发场景下问题解决思路

高并发指的是在单位时间内,瞬时流量激增,系统需要同时处理大量并行的请求或操作。这种情况通常出现在面向大量用户或服务的分布式系统中,尤其是当用户请求高度集中时,比如促销活动、秒杀活动、注册抢课、热点事件、定时任务调度等。

在高并发发生时,系统可能存在以下问题:
1.系统性能维度

  • 性能瓶颈:高并发可能导致系统资源(如CPU、内存、磁盘I/O、网络带宽)达到瓶颈,影响整体性能。
  • 响应延迟:系统处理请求的响应时间可能因并发量增加而延长,影响用户体验。
  • 系统过载:超出系统设计容量的并发请求可能导致系统过载,甚至宕机。
  • 容错性差:在高并发下,系统的容错性受到考验,单点故障可能导致整个服务不可用。

2.用户行为维度

  • 不可预测性:用户行为在高并发期间可能变得难以预测,导致难以准确评估系统负载。
  • 用户操作冲突:大量用户同时进行操作可能导致冲突,如抢票、抢单等场景。
  • 用户体验下降:由于系统响应变慢,用户体验可能显著下降。

3.数据处理维度

  • 数据不一致:在高并发写入时,缺乏合适的锁机制可能导致数据不一致。
  • 事务管理困难:高并发环境下,保持事务的ACID属性变得更加困难。
  • 数据库压力:高并发可能导致数据库连接数过多,查询和事务处理速度下降。

二.策略

为了应对高并发带来的压力,在高并发场景下,系统设计和优化可以从以下几个维度进行调整:

1. 架构设计维度

  • 服务拆分:将单体应用拆分成多个微服务,实现服务的独立扩展和维护。
  • 负载均衡:使用硬件或软件负载均衡器,如Nginx或HAProxy,分配网络流量和请求。
  • 无状态设计:确保应用服务器无状态,可以水平扩展。无状态设计是构建可伸缩、高可用系统的重要原则,特别是在高并发场景下。在无状态设计中,服务器不会存储任何关于客户端请求的信息,每个请求都是独立的,不依赖于之前的任何请求。

2. 数据库与存储优化维度

  • 数据库优化:对数据库进行定期的维护,如优化索引、更新统计信息。
  • 缓存应用:使用缓存减少数据库访问,如Redis进行热点数据缓存。
  • 存储优化:使用SSD代替HDD,提高I/O效率;考虑使用分布式存储系统。

3. 缓存策略维度

  • 多级缓存:实现应用层、服务层和数据库层的多级缓存机制。
  • 缓存淘汰策略:合理配置缓存淘汰策略,如LRU(最近最少使用)。
  • 热点数据优化:对频繁访问的数据进行特殊缓存处理。

4. 代码与应用优化维度

  • 异步处理:将非实时性的任务异步化,使用消息队列如Kafka或RabbitMQ。
  • 代码审查:定期进行代码审查,优化代码逻辑和结构。
  • 资源池:使用线程池、数据库连接池等资源池技术,提高资源利用效率。

5. 运维与监控维度

  • 实时监控:部署实时监控系统,如Prometheus或Zabbix,监控系统性能指标。
  • 日志管理:集中管理日志,使用ELK(Elasticsearch, Logstash, Kibana)堆栈进行日志分析。
  • 自动扩缩容:结合云服务提供的自动扩缩容功能,根据流量自动调整资源。

通过上述维度的策略实施,可以显著提升系统在高并发环境下的性能和稳定性。然而,每个系统的具体场景和需求都有所不同,因此在实施优化时需要根据实际情况进行定制化的调整。

三.例子

在大学抢课场景,课程的人数限制为30个学生,系统面临的主要问题包括:

  1. 高并发处理:在抢课开始时,系统可能会收到大量并发请求,需要设计以承受这种瞬时流量。
  2. 数据一致性:确保在高并发下,课程的选课名额不会超卖。
  3. 公平性:确保所有学生在抢课开始时都有机会选到课程。
  4. 系统稳定性:在高负载下,系统需要保持稳定,避免宕机。

领域模型:

  • Course:代表一门课程,包含课程ID、课程名称、剩余名额等属性。
  • Student:代表学生,包含学生ID、姓名等属性。
  • Enrollment:代表选课记录,包含学生ID、课程ID、选课时间等信息。

实现逻辑:

  1. 初始化课程:在系统中预先定义好每门课程的信息,包括课程ID、课程名称、容量等。
  2. 发布课程:将课程信息发布到选课系统中,学生可以查看到可选用课的列表。
  3. 学生选课:学生发送选课请求到系统。
  4. 获取分布式锁:系统尝试获取对应课程的分布式锁,确保同时只有一个请求能修改名额。
  5. 检查名额:检查Redis中该课程的剩余名额是否大于0。
  6. 更新名额:如果名额足够,更新Redis中该课程的剩余名额,并记录选课信息到数据库。
  7. 释放锁:完成名额更新后,释放分布式锁。
  8. 返回结果:向学生返回选课成功或失败的结果。

Demo

以下是使用Spring Boot和Redis实现大学抢课逻辑的示例代码

CourseController.java - REST 控制器用于处理课程注册请求:

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/courses") // 定义API的基础路由
public class CourseController {@Autowiredprivate CourseService courseService; // 注入课程服务类@PostMapping("/{courseId}/enroll") // 定义POST请求,用于抢课操作public ResponseEntity<?> enrollStudent(@PathVariable("courseId") String courseId, // 课程ID作为路径参数@RequestParam("studentId") String studentId) { // 学生ID作为请求参数boolean result = courseService.enroll(courseId, studentId); // 调用服务类的方法进行抢课if (result) {return ResponseEntity.ok("Enrollment successful!"); // 如果成功,返回成功响应} else {return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("Course is full."); // 如果失败,返回服务不可用响应}}
}

CourseService.java - 服务类使用Redis进行分布式锁控制:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;@Service
public class CourseService {@Autowiredprivate StringRedisTemplate redisTemplate; // 注入Redis字符串模板类@Autowiredprivate EnrollmentRepository enrollmentRepository; // 注入选课记录的持久层接口private static final String LOCK_SCRIPT = // 定义Lua脚本用于获取锁"if redis.call('set', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) == 1 then return 1 else return 0 end";public boolean enroll(String courseId, String studentId) {String lockKey = "course:" + courseId + ":lock"; // 定义锁的keyString studentKey = "course:" + courseId + ":student:" + studentId; // 定义学生的key// 使用Redis的Lua脚本原子地尝试获取锁,使用随机值和1000ms超时Boolean acquiredLock = redisTemplate.execute(new DefaultRedisScript(LOCK_SCRIPT),Collections.singletonList(lockKey),studentId,String.valueOf(1000L));if (Boolean.TRUE.equals(acquiredLock)) {try {// 检查学生是否已经选过这门课程if (redisTemplate.opsForSet().isMember(studentKey, studentId)) {return false;}// 检查剩余座位数Integer remainingSeats = redisTemplate.opsForValue().increment("course:" + courseId + ":seats", -1);if (remainingSeats >= 0) {// 选课成功,将学生添加到选课集合中redisTemplate.opsForSet().add(studentKey, studentId);// 保存选课记录Enrollment enrollment = new Enrollment(studentId, courseId);enrollmentRepository.save(enrollment);return true;} else {// 恢复座位数,因为课程已满redisTemplate.opsForValue().increment("course:" + courseId + ":seats", 1);return false;}} finally {// 总是在finally块中释放锁,以防止锁泄露redisTemplate.delete(lockKey);}} else {return false;}}
}

EnrollmentRepository.java - 持久层接口用于管理选课记录:

import org.springframework.data.jpa.repository.JpaRepository;public interface EnrollmentRepository extends JpaRepository<Enrollment, Long> {// JPA/JDBC方法用于管理选课记录
}

CourseService中,我们使用Lua脚本来尝试获取课程的锁。如果锁被成功获取(acquiredLocktrue),我们进一步检查学生是否已经选过这门课程。如果没有,我们减少座位数,并且如果座位仍然可用,我们将学生添加到选课集合中并保存选课记录。如果课程已满或者学生已经选过这门课程,我们释放锁并返回false

请注意,上述代码知识一个思路演示,在生产系统中,还需要处理各种边缘情况和潜在的异常。可能还需要适当配置StringRedisTemplateEnrollmentRepository,包括在Spring Boot应用程序中设置必要的依赖和注解。
此外,用于锁定和跟踪学生请求的Redis键需要精心设计,以避免冲突,并确保它们可以被轻松管理和在不再使用后清理。

相关文章:

【代码笔记】高并发场景下问题解决思路

高并发指的是在单位时间内&#xff0c;瞬时流量激增&#xff0c;系统需要同时处理大量并行的请求或操作。这种情况通常出现在面向大量用户或服务的分布式系统中&#xff0c;尤其是当用户请求高度集中时&#xff0c;比如促销活动、秒杀活动、注册抢课、热点事件、定时任务调度等…...

【Docker系列】Linux部署Docker Compose

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

基于SSM的文化遗产的保护与旅游开发系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的文化遗产的保护与旅游开发系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…...

整合springboot-mybatis时,MySQL数据库无法连接问题

整合springboot-mybatis时&#xff0c;MySQL数据库无法连接问题 解决步骤 先手动停止MySQL服务&#xff0c;在cmd后的控制台输入services.msc 找到MySql停止服务 修改配置文件&#xff0c;跳过验证 修改MySQL安装目录下的my.ini配置文件&#xff0c;使登录时跳过权限检查&a…...

C语言循环队列

以下是一个使用 C 语言实现的简单循环队列示例&#xff1a; #include <stdio.h> #include <stdlib.h>#define MAX_SIZE 5// 定义循环队列结构体 typedef struct {int items[MAX_SIZE];int front, rear; } Queue;// 初始化队列 void initQueue(Queue *q) {q->fr…...

Docker运行出现iptables: No chain/target/match by that name报错如何解决?

在尝试重启 Docker 容器时遇到的错误信息表明有关 iptables 的配置出了问题。这通常是因为 Docker 需要配置网络&#xff0c;而 iptables 规则没有正确设置或被意外删除。具体到你的错误信息中&#xff0c;报错 iptables: No chain/target/match by that name 表示 Docker 尝试…...

力扣 122. 买卖股票的最佳时机 II python AC

动态规划 class Solution:def maxProfit(self, prices):pre float(inf)ans 0for now in prices:if now > pre:ans now - prepre nowreturn ans定义一个变量保存上一步位置最小的数值&#xff0c;来模拟dp --遍历股票数值 --如果当前数值大于上一次&#xff0c;将股票卖…...

F5 BIG-IP Next Central Manager SQL注入漏洞(CVE-2024-26026、CVE-2024-21793)

0x01 产品简介 BIG-IP Next Central Manager是BIG-IP Next的原生默认用户界面,它可跨平台管理BIG-IP Next实例。BIG-IP Next是F5 Networks公司推出的一款下一代BIG-IP软件,提供了多云应用安全和应用交付服务。 0x02 漏洞概述 CVE-2024-26026:BIG-IP Next Central Manager…...

Python3 笔记:循环结构 for语句

for语句是Python语言中构造循环结构程序的语句之一。 Python中for语句是通过循环遍历某一序列对象&#xff08;字符串、列表、元组或字典&#xff09;来构建循环&#xff0c;循环结束的条件就是对象被遍历完。 for循环基本语法格式&#xff1a; for 循环变量 in 遍历对象: …...

信息化与数字化的区别在哪里?

信息化与数字化虽然密切相关&#xff0c;但它们在核心理念、实施范围、目标定位、以及对企业的影响上存在本质区别&#xff1a; 1.中心与目标不同&#xff1a; • 信息化通常以流程为中心&#xff0c;致力于提高工作效率&#xff0c;通过信息技术优化和自动化企业内部的流程。…...

记录MySQL数据库查询不等于xxx时的坑

目录 一、背景 二、需求 三、方法 四、示例 一、背景 在使用MySQL数据库查询数据时&#xff0c;需要查询字段name不等于xxx的记录&#xff0c;通过where name ! xxx查询出来的记录不符合预期&#xff0c;通过检查发现少了name字段为null的记录&#xff0c;后经查询得知在My…...

QT的创建,发现编译器有一个黄色三角形感叹号,提示说Cmake配置错误,该怎么办?

确保你安装了Cmake 2.如果你电脑之前已经装了Cmake&#xff0c;那么在qt安装中&#xff0c;即便你选择了Cmake版本&#xff0c;但依旧不会修改电脑的Cmake版本。这时候就会出现黄色箭头。在勾勾的地方会有一个黄色感叹符号&#xff08;我已经解决了&#xff0c;所以没有显示&a…...

0506libMaven项目

0506libMaven项目包-CSDN博客 数据库字段 界面需求...

HTML飘落的花瓣

目录 写在前面 HTML​​​​​​​简介 完整代码 代码分析 系列推荐 写在最后 写在前面 本期小编给大家推荐HTML实现的飘落的花瓣&#xff0c;无需安装软件&#xff0c;直接下载即可打开~ HTML​​​​​​​简介 HTML&#xff08;Hypertext Markup Language&#xff…...

一个小调整,竟然让交换机、路由器的CPU占用率降低了50%

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 在信息时代下&#xff0c;不仅仅在网络工程领域&#xff0c;高CPU占用率都是一个非常常见的问题&#xff0c;…...

echarts树图 改文本显示的地方的样式

树图改文本显示的时候的样式 虽然有点越改越丑 其中有一些失败的尝试 forammter 无法识别html元素 所以对于tooptips有用的html元素定义获取返回在这里写的话是不生效的 rich配置项里面的backgroundColor官方说支持 html元素和canvas元素 已经图片url 没有详细试验 官网地址 h…...

MYDB运行环境的搭建

前言 再将该项目跑起来之前&#xff0c;我想你的环境应该是准备的差不多啦&#xff01;只需要稍稍的配置一下即可。 我在本地已经跑通了&#xff0c;说是兼容JDK8&#xff0c;但我本地刚好有11就用了11啦&#xff0c;跑起来的方法在仓库的 readme 里写的很清楚。 在运行mvn c…...

Flink Stream API实践

目录 Flink程序的基本构成 获得执行环境&#xff08;environment&#xff09; 加载/初始化数据&#xff08;source&#xff09; 基于文件 基于socket 基于集合 自定义 转换操作&#xff08;transformation&#xff09; 基本转换 物理分区 任务链和资源组 名称和描述…...

AI图像生成-原理

一、图像生成流程总结 【AI绘画】深入理解Stable Diffusion&#xff01;站内首个深入教程&#xff0c;30分钟从原理到模型训练 买不到的课程_哔哩哔哩_bilibili 二、如果只是用comfy UI生成图片 1、找到下面几个文件&#xff0c;把对应模型移动到对应文件夹即可使用 2、选择对…...

【JavaScript】尺寸和位置

DOM对象相关的尺寸和位置属性 用于获取和修改元素在页面中的尺寸和位置。 只读属性&#xff1a; clientWidth和clientHeight&#xff1a;获取元素可视区域的宽度和高度&#xff08;padding content&#xff09;&#xff0c;不包括边框和滚动条。 offsetWidth和offsetHeight…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...