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

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

在高并发发生时,系统可能存在以下问题:
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键需要精心设计,以避免冲突,并确保它们可以被轻松管理和在不再使用后清理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven 插件使用

1.spring-boot-maven-plugin 我们直接使用 maven package &#xff08;maven自带的package打包功能&#xff09;&#xff0c;打包Jar包的时候&#xff0c;不会将该项目所依赖的Jar包一起打进去&#xff0c;在使用java -jar命令启动项目时会报错&#xff0c;项目无法正常启动。…

开源相机管理库Aravis例程学习(七)——chunk-parser

开源相机管理库Aravis例程学习&#xff08;七&#xff09;——chunk-parser 简介例程代码函数说明arv_camera_create_chunk_parserarv_camera_set_chunksarv_chunk_parser_get_integer_value 简介 本文针对官方例程中的&#xff1a;05-chunk-parser做简单的讲解。并介绍其中调…

kali linux更新卡在libc6:amd64 (2.37-15)

适配于linux的windows子系统&#xff0c;wsl2&#xff0c;安装kali linux&#xff0c;运行 sudo apt update 卡在&#xff1a;Setting up libc6:amd64 (2.37-15) … 关机重启、重新修复执行也不行 解决办法&#xff1a;kill当前apt进程或者关机重启kali-linux&#xff0c;然…

【系统架构师】-选择题(十二)计算机网络

1、网闸的作用&#xff1a;实现内网与互联网通信&#xff0c;但内网与互联网不是直连的 2、管理距离是指一种路由协议的路由可信度。15表示该路由信息比较可靠 管理距离越小&#xff0c;它的优先级就越高&#xff0c;也就是可信度越高。 0是最可信赖的&#xff0c;而255则意味…

MySQL变量的定义与使用(一)

一、标识符的命名规范 1、不能以数字开头 2、不能使用关键字 3、只能使用_和$符号&#xff0c;不允许使用其他符号 二、定义MySQL变量的方法 set userName"鹅卵石"; #读取变量 select userName as 名称; #读取时包含赋值操作 select userName:喜羊羊 as 赋值查询名…

【JavaScript】内置对象 - 数组对象 ① ( 数组简介 | 数组创建 | 数组类型检测 )

文章目录 一、数组对象1、数组简介2、数组创建3、数组检测 - Array.isArray() 方法4、数组检测 - instanceof 运算符 Array 数组对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array 一、数组对象 1、数组简介 在 JavaScr…

(三十八)第 6 章 树和二叉树(二叉树的二叉线索存储)

1. 背景说明 2. 示例代码 1) errorRecord.h // 记录错误宏定义头文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 从文件路径中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ? strrc…

Html生成自定义函数的图形(2024/5/10)

大概效果如下&#xff1a; 可以自定义函数和x的定义域。 我们可以使用数学表达式解析库来解析用户输入的函数方程&#xff0c;并根据给定的 x 区间计算函数的值&#xff0c;然后使用图表库绘制图形。 在这里&#xff0c;我将使用 math.js 库来解析数学表达式&#xff0c;并使…

探索计算之美:HTML CSS 计算器案例

本次案例是通过HTML和CSS&#xff0c;我们可以为计算器赋予独特的外观和功能&#xff1b; 在这个计算器中&#xff0c;你将会发现&#xff1a; 简洁清晰的界面设计&#xff0c;使用户能够轻松输入和查看计算结果。利用HTML构建的结构&#xff0c;确保页面具有良好的可访问性和…

【全开源】JAVA上门家政服务系统源码微信小程序+微信公众号+APP+H5

功能介绍 用户端&#xff1a;精准分类、支持家政、维修、万能服务、一口价、报价、线上、各类家政服务、优惠专区、师傅入驻、商家入驻、我的需求、补费明细、我的投诉 师傅端&#xff1a;接单池、消息通知、接单管理、今日订单、师傅入驻、我的钱包、实名认证 商家端&#…

HTTPS 原理和 TLS 握手机制

HTTPS的概述与重要性 在当今数字化时代&#xff0c;网络安全问题日益凸显&#xff0c;数据在传输过程中的安全性备受关注。HTTPS 作为一种重要的网络通信协议&#xff0c;为数据的传输提供了强有力的安全保障。它是在 HTTP 的基础上发展而来&#xff0c;通过引入数据加密机制&a…

流量分析(一)

数据库类流量分析 MySQL流量 常规操作&#xff0c;查找flag ctfhub{} 注意要选择字符集 Redis流量 查找ctfhub结果没找到 尝试把其变成十六进制继续进行查找 看到了前半段flag 接着往下看 找到了后半段的flag MongoDB流量 还是一样查找ctfhub 字符串没找到 转成十六进制也没…

c 在线教育系统论文,在线教育需要在哪些渠道做付费推广呢?

随着在网上学习的人越来越多&#xff0c;很多在线教育公司都开发了属于自己的平台。如果只做开发&#xff0c;不去做运营推广的话&#xff0c;这个在线平台就等于是白做了。那么在线教育需要在哪些渠道做付费推广呢? 1、官网广告推荐位 Banner作为一款展示型页面横幅广告&…

Spring状态机的实现原理和业务场景

Spring Statemachine 是 Spring Framework 的一部分&#xff0c;它提供了一种实现状态机的方式&#xff0c;允许开发者定义状态机的状态、事件、行为和转换。状态机是一种计算模型&#xff0c;它可以根据一系列规则从一个状态转移到另一个状态。以下 V 哥将从Spring状态机的基本…

OpenVoiceV2本地部署教程,苹果MacOs部署流程,声音响度统一,文字转语音,TTS

最近OpenVoice项目更新了V2版本&#xff0c;新的模型对于中文推理更加友好&#xff0c;音色也得到了一定的提升&#xff0c;本次分享一下如何在苹果的MacOs系统中本地部署OpenVoice的V2版本。 首先下载OpenVoiceV2的压缩包&#xff1a; OpenVoiceV2-for-mac代码和模型 https:…

Kitti数据集再识(官网阅读)

KITTI数据集中真值与标定参数 0. 前言 为了再研KITTI数据集及方便下载文件,特地买了梯子,心疼人民币QWQ~555 1. KITTI-home Welcome to the KITTI Vision Benchmark Suite! 我们利用我们的自动驾驶平台开发新颖的具有挑战性的真实世界计算机视觉基准。我们感兴趣的任务是…

interview_bak

flink内存管理 JVM 存在的几个问题: Java 对象存储密度低。一个只包含 boolean 属性的对象占用了16个字节内存:对象头占了8个,boolean 属性占了1个,对齐填充占了7个。而实际上只需要一个bit(1/8字节)就够了。Full GC 会极大地影响性能,尤其是为了处理更大数据而开了很大…

安装openssh-server,提供远程ssh

安装openssh-server&#xff0c;提供远程ssh 1.检查自己是否安装了openssh-server dpkg -l | grep ssh如果输出内容有openssh-server&#xff0c;说明已经安装过了&#xff0c;可以跳过下一步 2.安装openssh-server 由于ubuntu自带ssh客户端&#xff0c;只需要安装openssh-se…

mysql -- CRUD

CRUD MySQL是一个广泛使用的开源关系数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它支持通过SQL&#xff08;Structured Query Language&#xff09;语言进行数据的管理。在MySQL中&#xff0c;CRUD是一个常见的术语&#xff0c;代表了数据管理的四个基本操作&am…

图片转图标(ICO)的工具软件

目前常用的ICO转换方式大多都是网页在线转换&#xff0c;没网就无法使用了。自己编写了一款小软件&#xff0c;可以将各种格式图片转为ICO图标。 目前支持PNG,BMP,JPG,JPEG,GIF等格式的图片转换成ICO&#xff0c;支持的尺寸有常用的16*16&#xff0c;24*24&#xff0c;32*32&am…