本文参考自
本章将介绍仿12306售票系统实战开发的开发环境、项目核心技术和功能、项目模块和架构设计、开发所需前置知识,若想直接开始编写代码实现,请关注作者,看后面的第二章——项目实现
一、开发环境
- 后端:
- JDK 17
- Springboot 3.0.0
- SpringCloud Alibaba 2022.0.0.0
- 第三方依赖,如Mybatis等,使用升级后适配Springboot3的版本
- 前端:
- Vue3
二、项目技术亮点概括
为什么使用最新版本?
学习要激进,实际项目要滞后(市场主流还是使用JDK1.8那套)
技术亮点主要就是高并发技术
售票系统需要实现持续高并发,不停的刷票,决不能超卖
12306是如何解决高并发问题?
-
提高处理能力: QPS和TPS
堆积硬件;引入第三方软件Gemfire;算法(模型、逻辑)
Gemfire:商业软件,分布式内存数据库,使得查询速度从15秒降到0.2秒
QPS(Queries Per Second)和 TPS(Transactions Per Second)是衡量系统性能的重要指标:
- QPS(Queries Per Second):指的是每秒钟所处理的查询数量,通常用来衡量系统对于短时、瞬时请求的处理能力,比如网络请求、数据库查询等。
- TPS(Transactions Per Second):指的是每秒钟所处理的事务数量,事务可以是一个或多个相关操作的集合,用来完成一个业务功能。TPS常用来衡量系统对于业务操作的处理能力,比如支付交易、订单处理等。
QPS更强调系统的查询处理能力,而TPS更侧重系统对业务操作的处理能力。在不同的场景下,可以根据具体需求选择监控并优化QPS或TPS来提升系统性能。
-
削峰
业务:验证码、分时段、排队
技术:限流、异步
三、项目业务逻辑难点概括
-
选座逻辑
实现类似12306的选座逻辑
使用位运算算法,既快又准的得到符合要求的座位
-
12306:
-
本项目:
-
-
动态库存
当上海——北京,被买,则是1张票
当上海到南京,南京到上海被买,则是2张票
-
线上线下
即可线上买票,也可线下买票
四、核心功能
最高并发:余票查询
业务逻辑最复杂:车票购买
五、功能模块划分
-
网关模块
路由转发、登录校验
-
会员模块
会员、乘客、已购买的车票
-
业务模块
所有的车次数据、余票信息
-
跑批模块
管理定时任务,页面启停
-
web模块
会员相关界面
-
admin模块
管理员相关界面
六、整体架构设计
- 业务、会员、跑批分别为不同的服务,且数据库相互隔离(做一定的数据冗余)
- common主要是公共的工具类,generator为代码生成器
- springcloud alibaba组件:nacos是注册中心,seata是分布式事务,sentinel是限流
七、数据库表
1. 会员模块
- 会员表:手机号
- 乘客表:会员ID,姓名,身份证,旅客类型
- 车票表:会员ID,乘客ID,乘客姓名,日期,车次信息,座位信息
2.业务模块
- 车站表:站名,站名拼音
- 车次表:车次编号,车次类型,始发站,出发时间,终点站,到站时间
- 到站表:车次编号,站名,进站时间,出站时间,停站时长,里程
- 车箱表:车次编号,箱号,座位类型,座位数,排数,列数
- 座位表:车次编号,箱号,排号,列号
- 每日车次表:日期,基础车次信息
- 每日到站表:日期,基础到站信息
- 每日车箱表:日期,基础车箱信息
- 每日座位表:日期,基础座位信息,销售详情
- 每日余票表:日期,车次编号,出发站,出发时间,到达站,到站时间,各种座位的余票信息
3.其他
- quartz相关表
- seata相关表
八、持续秒杀高并发技术
1.前端
-
针对静态资源做CDN
CDN(Content Delivery Network)技术是一种通过在全球各地部署服务器节点来加速网络内容传输的技术。通过在靠近用户的服务器节点上缓存内容,CDN技术能够减少网络延迟,提高网站的加载速度和性能。当用户请求访问网站时,CDN会自动将内容从最接近用户的服务器节点传输给用户,而不是从远程服务器传输,从而提高用户体验并减轻原始服务器的负载压力。
-
页面静态化
页面静态化是指将动态生成的网页内容转换为静态文件,并保存在服务器的本地存储空间或CDN节点上,从而加快网页加载速度和提高网站性能的技术。通过页面静态化,服务器无需每次请求时都重新生成页面内容,而是直接返回预先生成好的静态文件,减少了服务器的计算压力和数据库访问次数,提高了网站的并发访问能力和用户响应速度。页面静态化技术有助于改善网站的用户体验,减少加载时间,提高页面渲染速度。
-
倒计时&loading
防止用户不断刷新/点击秒杀,造成后端更大的压力
-
使用验证码削峰
2.后端
-
微服务-服务拆分
热点接口做成单独的服务
-
负载均衡
-
限流降级
-
缓存
-
令牌
-
异步处理
3.数据库
- 分库:业务分库、读写分离
- 分表:横向分表(按地区/时间分)、纵向分表(把一张完整的表,纵向切成两张表)
- 冗余设计(反范式,空间换时间)
- 分布式数据库
4.其他
- 分时段秒杀
- 弹性扩容(自动扩容有时候反应比较慢,不适合突发的大流量请求,所以秒杀之前需要提前扩容好;但是在秒杀后,他可以自动回收,降低成本
- 候补+排队
九、SpringBoot3&JDK9~17新特性详情
1.JDK9新特性——模块化开发(用的较少)
Java8应用程序将包作为顶级组件,Java9应用程序将模块作为顶级组件。
使用module-info.java来声明一个模块,一个模块只能有一个文件,且在顶层包同目录下
使用exports来声明可以被外部引用的包,可以有多个exports语句
使用requires来声明依赖的外部的模块,可以有多个requires语句
2.JDK10新特性——var局部变量推导
- 必须能推导出实际类型
- 只能用于局部变量
3.JDK11新特性——单文件程序
原来:使用javac生成.class文件,然后在.class文件下用java命令将其打开
现在:直接命令运行:java xxx.java(必须带.java)
4.JDK11新特性——shebang脚本
将java文件改成sh后缀,使用如下命令可运行
java --source 11 xxx.sh
什么是shebang
#!符号可以叫做shebang,翻译成释伴,即"解释伴随行"的简称,同时又是shebang的音译
以指令#!/bin/bash开头的文件,在执行时会实际调用/bin/bash程序来执行
5.JDK14新特性——文本块
// 传统字符串写法
String json = "{\n" +
"\tname: \"TEST\"\n" +
"}";
System.out.println(json);
// 文本块写法
String json1 = """
{
name: "TEST"
}
""";
System.out.println(json1);
6.JDK14新特性——instanceof增强
Object a = "123";
if (a instanceof String) {
String b = (String) a;
System.out.println(b);
}
if (a instanceof String b) {
System.out.println(b);
}
7.JDK14新特性——空指针提示
-
传统报错
Exception in thread "main" java.lang.NullPointerException at com.jiawa2.Jiawa2.main(Jiawa2.java:46)
-
新报错
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.List.size()" because "a" is null at com.jiawa2.Jiawa2.main(Jiawa2.java:46)
8.JDK16新特性——record类
record是一个final类,初始化后就不能修改属性值
自动生成toString, hashCode, equals方法
public record TestRecord(String name, String password) {
}
TestRecord testRecord = new TestRecord("test","111");
9.JDK17新特性——sealed类
- 痛点:一个类被哪些子类继承了,很难查,随时有可能继续被继承
- sealed可以对类的继承做显式的管理,一个类被哪些类继承,一眼就能看得清。
- 父类如果是sealed类,则必须至少有一个子类
- sealed类的子类,必须是final,sealed,non-sealed之一
sealed类封装类或叫密封类
密封类的目的是为了限制子类的过度使用,父类的开发者必须声明哪些子类可以继承该父类,以确保不会出现未限定的子类继承父类,导致程序出现预料之外的问题密封类及其允许的子类必须属于同一个模块。
每个允许的子类都必须直接继承密封类。
每个允许的子类都必须使用final、sealed或non-sealed修饰符中的一个来描述:
- 允许的子类声明为 final 表示它无法再扩展。
- 允许的子类声明为sealed表示它可以以一种受限制的方式进一步扩展。
- 允许的子类声明为non-sealed表示它可以任意的扩展。
显式声明Jiawa1只能被Jiawa2集成:
public sealed class Jiawa1 permits Jiawa2 {
}
non-sealed:恢复隐式规则
10.JDK17新特性——switch增强
-
旧版本:
if (data.get("key") instanceof String s) { log.info(s); } else if (data.get("key") instanceof Double s) { log.info(s); } else if (data.get("key") instanceof Integer s) { log.info(s); }
-
新版本:
switch (data.get("key1")) { case String s -> log.info(s); case Double d -> log.info(d.toString()); case Integer i -> log.info(i.toString()); default -> log.info(""); }
11.SpringBoot3——AOT与JIT介绍
JIT(Just-in-Time,实时编译)一直是Java语言的灵魂特性之一,与之相对的AOT(Ahead-of-Time,预编译或提前编译)方式
AOT的优点
- 在程序运行前编译,可以避免在运行时的编译性能消耗和内存消耗
- 可以在程序运行初期就达到最高性能,程序启动速度快
- 运行产物只有机器码,打包体积小
AOT的缺点
- 由于是静态提前编译,不能根据硬件情况或程序运行情况择优选择机器指令序列,理论峰值性能不如JIT
- 没有动态能力(如AOP)
- 同一份产物不能跨平台运行
12.JIT在高并发场景中的生产问题
现象:热点应用重启后,出现业务超时,几分钟后恢复正常
解决方法:
- 预热:初始让程序自动运行热点代码几百次
- 流量控制:启动时小流量,运行几分钟后再放到正常流量
13.SpringBoot3——GraalVM代替JDK实现AOT
-
GraalVM下载:
https://github.com/graalvm/graalvm-ce-builds/releases/tag/vm-22.3.0
JAVA_HOME:给一些第三方用,例如Tomcat,会读取这里的路径
Path:在命令行可以获取JDK信息
-
安装native-image(用来打包exe(windows版本))
-
在线安装
gu install native-image(powershell报错,cmd正常)
有可能会超时报错,多试几次 -
手动安装
下载:https://github.com/graalvm/graalvm-ce-builds/releases/tag/vm-22.3.0
命令行:gu install -L 你的下载位置 -
查看安装结果
gu list
-
-
新建SpringBoot3项目
使用IDEA新建SpringBoot项目,版本号:3.0.0 -
安装Visual Studio 2022
下载社区版,安装时勾选C++桌面开发
-
GraalVM AOT打包
跳到项目所在目录,使用x64 Native Tools Command Prompt for VS 2022,执行:mvn -Pnative native:compile