基于SpringCloudAliBaba技术栈的分布式选课系统
基于SpringCloud Alibaba 分布式微服务选课系统的性能优化

1.引言
1.1编写目的
为了解决学生选课时系统崩溃 宕机的问题 特此编写本系统 实现选课系统的高可用与负载均衡
1.2背景
我们学校的选课系统人一多就会崩溃
分析原因还是因为一瞬间大量人涌入选课系统 系统扛不住高并发而宕机
本系统在此前期下 准备自己开发一款选课系统
使用sentinel作为服务熔断和降级框架使用redisson作为分布式锁使用Nginx+SpringCloud Gateway 做负载均衡``使用docker+k8s做持久化自动部署保证几万学生在同一时间下 访问系统不会崩溃 宕机使用JWT作为(Token)作为系统的身份校验 授权与认证采用前后端分离的方式部署该系统,小组分工明确
1.3定义
(列出本文件中用到的专门术语的定义和外文首字母组词的原词组。)
前端
后端
部署
测试运维
1.4参考资料
Spring官方文档: https://spring.io/
MyBatisPuls官方文档: https://baomidou.com/
Nacos官方文档: https://nacos.io/zh-cn/
Sentinel官方文档: https://sentinelguard.io/zh-cn/
SpringCloud中文文档: https://www.springcloud.cc/
Docker官方文档:https://www.docker.com/
Vue官方文档:https://cn.vuejs.org/
elementUI官方文档: https://element.eleme.cn/#/zh-CN
HuTools官方文档: https://hutool.cn/docs/#/
Kubernetes中文社区: http://docs.kubernetes.org.cn/
Cloud-Platform框架文档: https://gitee.com/geek_qi/cloud-platform/blob/master/dev-doc.md
2.项目概述
2.1 工作内容
完成选课的发布 学生登录系统 及学生选课 功能 学生可查看已选课程
扩展功能: 本校学生可登陆进本系统查看其课程表 校外考试 校内考试成绩 及绩点
2.2小组成员
软工1905 风 离: 项目后端 技术选型 文档编写 项目部署 运维 测试技术水平: 掌握常用JAVA后端技术栈 能独立开发出分布式微服务系统 有过部署经验
软工1904 苏才华: 项目前端 思路提供者 UI设计师 前端大佬技术水平:
软工1905 任威: 项目组织者 思路提供者 LOGO设计师技术水平:
2.3 产品
基于
SpringCloudalibaba分布式微服务 高并发选课系统
2.3.1 程序
(列出需移交给用户的程序的名称,所用的编程语言及存储程序的媒体形式,并通过引用有关文件,逐项说明其功能和能力。)
2.3.2 文件
(列出需移交给用户的每种文件的名称及内容要点。)
2.3.3 服务
(列出需向用户提供的各项服务,如培训安装、维护和运行支持等,应逐项规定开始日期、所提供支持的级别和服务的期限。)
2.3.4 非移交的产品
程序源码
2.4 验收标准
(对于上述这些应交出的产品和服务,逐项说明或引用资料说明验收标准。)
3. 实施计划
3.1工作任务的分解与人员分工
(对于项目开发中需完成的各项工作,从需求分析、设计、实现、测试直到维护,包括文件的编制、审批、打印、分发工作,用户培训工作,软件安装工作等,按层次进行分解,指明每项任务的负责人和参加人员。)
各项工作 负责人 参与人员 需求分析 风离 苏才华,任威 数据库设计 风离 苏才华,任威 后端接口实现 风离 无 前端接口实现 苏才华 无 前后端联调 风离,苏才华 无 测试 风离 苏才华,任威 维护 风离 无 文件的打印、分发工作 文件的编制、审批 用户培训工作 软件安装工作 风离 苏才华,任威
3.2 接口人员
接口类型 人员 职责 负责本项目同用户的接口 负责本项目同本单位各管理机构 负责本项目同各分合同负责单位的接口
3.3 进度
- 需求分析与数据库设计 2.27
- 项目前后端框架选取与搭建完毕 2.28
- 解决前后端跨域联调 2.28
- 解决Token传输问题 用户信息接口完成 3.01
- 整合Redisson完成课程信息发布 已选课程信息接口完成 整合SpringCache完成缓存优化 3.02
- 全部选课预热已完成(已测试) 3.04
- 选课已解决(待高并发测试)3.06
- 解决重复选课 删除缓存预热完成 发布选课班 展示待参与选课班级完成 3.07
- 实现线上线下环境切换 整合MongoDB实现教务系统与本地选课系统的整合 3.09
- 实现全云端配置文件 3.10
- 创建高并发测试案例 并通过测试 3.11
3.4 预算
暂无
3.5关键问题
1: 中间件RabbitMQ宕机不可用问题
2:缓存数据库 Redis 持久化问题
3: 集群部署上线问题
4:高并发线下实测 待测
4.支持条件
4.1计算机系统支持
本地开发环境: Win10
远程部署环境: Linux - Centos 7
4.2需由用户承担的工作
使用选课系统
4.3需由外单位操供的条件
暂未
5.专题计划要点
待完成
我是分割线———————————
项目相关
项目截图及在线展示








技术选型
项目前端:
vue-element-admin
项目后端:
项目基础框架:
SpringCloud SpringCloudAlibaba SpringBoot MybatisPlus消息中间件:
RabbitMQ缓存数据库:
Redis SpringCache Redisson对象储存:
SpringAlibaba OSS安全框架:
Spring Security网关:
Spring Cloud Gateway远程调用RPC:
OpenFeign服务降级熔断:
SpringCloudAliBaba Sentinel服务注册中心与配置中心:
SpringCloudAliBaba Nacos链路追踪:
spring-cloud-sleuth-zipkin项目健康状态监控:
Spring Boot actuator SpringBoot Admin数据库及连接池:
Mysql Druid工具包:
Hutools FastJson日志:
Log4j项目脚手架:
开源项目Cloud-Platform定时任务框架:
Quartz项目协作
版本控制平台:
Gitee接口文档管理:
ApiFox远程办公:
ToDesk项目上线发布
部署环境:
阿里云 Linux Centos (2核4G)* 2+阿里云 Linux Centos (1核2G) * 2+腾讯云 Linux Centos (4核16G)* 1部署工具:
Docker + K8s + Jenkins测试工具:
Jmeter
本地部署运行说明
前置条件:
JDK1.8 Node.js 14.16.7 Maven 3.5.X Git初始化Git仓库: >
git init前端拉取命令:
git clone -b vue_dev https://gitee.com/fl1906249647/course-selection-system.git
- 下载依赖及运行(在下载目录下): npm install npm run dev
后端拉取命令:
git clone -b dev https://gitee.com/fl1906249647/course-selection-system.git
修改配置文件
yaml中所有的环境 Nacos RabbitMq Redis Mysql MongDB 账号密码端口为自己电脑本地环境配置
安装启动RabbitMQ (读者自行百度)
安装Nginx
安装启动MySql (读者自行百度)
安装启动Redis(读者自行百度)
安装启动MongDB(读者自行百度)
安装启动Nacos (读者自行百度)
启动Sentinel(在下载目录里:java -jar sentinelxxx.jar)
启动微服务顺序
远程部署运行说明
部署前端
采用
jenkins+docker+nginx自动部署至服务器 前端只要将代码提交至Gitee 即可自动部署到 远程服务器参考文章
部署后端
本地与线上环境切换
数据库设计
课程与课程班的对应关系

课程班与选课学生的对应关系

选课流程
所有流程图在线预览地址:
https://www.processon.com/view/link/6223834b0e3e74108ca0a57f
密码: I84H
核心流程1: 选课预热 发布选课信息



发布待选课程信息
传入待选课程班id 以及 最大选课人数
Redis缓存待选课程信息 及可选数量
这里可选数量与课程信息分开 依靠随机码相互连接
通过redisson加分布式锁
由于选课服务部署在集群,因此每个服务器都会同时将数据缓存到redis,但我们只需要让数据缓存一次。
因此不仅需要在缓存前
判断key的存在,还需要加分布式锁保证只有一条线程缓存数据。由于这种多线程同时缓存的情况只会出现一次,因此我们不采用默认的看门狗机制(默认30秒续期 直到该方法结束),而是
给锁加几秒钟过期时间就可。随机码如何防恶意请求:
前端将随机码拼在选课的url上,因此单纯结合课程班id发请求是无效的。选课开始时(定时任务)后端才将随机码返回给前端,只有选课开始才能抢课。
redis中分布式信号量的key是和课程班随机码绑定的,因此只有随机码正确才能查找到课程班对应的分布式信号量。
- 返回发布成功即可 这个时间应该比较长 大概3~4 秒 (但只要保证学生展示待选课程从Redis中读取 毫秒级响应即可)
核心2:学生选课

展示待选课程信息
老师立即可见
学生只有在选课时间开始时才可见
学生退选课程
解决项目中的问题
Redis
+
springboot连接远程redis出现 java.io.IOException: 远程主机强迫关闭了一个现有的连接
spring
redis:
host:
port: 6379
password:
database: 1
timeout: 60s
## springboot2.0之后将连接池由jedis改为lettuce
lettuce:
pool:
max-idle: 30
max-active: 8
max-wait: 10000
min-idle: 10Redis.conf
tcp-keepalive 300 # 保持长连接300s并重启Redis
Redis 重启后密码失效
Redis.conf
requirepass 密码 # 设置密码持久化 并重启Redis
Redis分布式锁本地连接远程失败
Caused by: org.redisson.client.RedisResponseTimeoutException: Redis server response timeout (3000 ms) occured after 3 retry attempts.
解决:
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer() // 使用单机模式
.setAddress("redis://" + redisHost + ":" + redisPort)
.setKeepAlive(true)
// 设置1秒钟ping一次来维持连接
.setPingConnectionInterval(1000)
.setPassword(redisPass);
return Redisson.create(config);
}
Nacos 配置中心不生效
导入这个依赖 原因: bootstrap.yml未生效
org.springframework.cloud spring-cloud-starter-bootstrap
quartz
springboot整合quartz遇到的错误
1、spring boot整合quartz执行多个定时任务时报:
org.quartz.ObjectAlreadyExistsException: Unable to store Job : ‘group1.job1’, because one already exists with this identification.
解决办法: 在初始化调度的时候clean一下: scheduler.clear();
项目 高并发本地测压
创建1000个测试用户并生成各自的token 存入user.txt文件等待测试
//@RequestParam(value = "date")Integer date,@RequestParam("size")Integer size |
创建线程组 1000个线程 3次循环

user.txt文件导入测试


清除缓存预热

选课预热 一门课 限选60人 (1000人并发访问)

查看选课状态

启动测试
查看结果树与报告



判断学生是否重复选课
SELECT * FROM
(SELECT `student_id`,COUNT(*) AS c
FROM st_courseclass_student GROUP BY `student_id`) t WHERE c>1;













