# train **Repository Path**: tangfh666/train ## Basic Information - **Project Name**: train - **Description**: 12306 project by tangfh - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-04-20 - **Last Updated**: 2024-06-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 唐峰辉 12306 ## 项目简介 **网站说明(参照12306售票核心功能,从0到1实现整体项目架构)** 本项目共有15张业务表,自制通用代码生成器,快速生成增删改查包含界面,减少无意义的增删改查时间。 购票流程看起来简单,但用了很多看不见的高并发技术,比如10万人抢1000张票: - 技术概览: 前后端分离 **Vue 3** + **微服务**(JDK 17 + SpringBoot 3)& **SpringCloud** Alibaba - 利用**CDN**,提高用户访问页面速度 - 利用**分布式缓存**,在秒杀开始前,提供高性能余票查询,同时要考虑缓存击穿、穿透、雪崩等问题 - 使用**第一层验证码**,纯前端验证码在前端削弱瞬时高峰,将100毫秒内10万人的请求,分散成1~2秒内10万人请求 - 使用**第二层验证码**,后端验证码,进一步分散请求,同时防止机器人抢票 - 使用**限流技术**减轻无谓请求,同时给用户快速失败响应(告知票没有了),将9万请求快速失败,变成1万请求抢1000张票 - 使用**令牌发放技术**,控制抢票量,同时防止机器人刷票,比如开放2000令牌,即变成8000请求快速失败,变成2000请求抢1000张票 - 使用**分布式锁技术**,防止超卖,即2000人抢1000张票,最终只能卖出1000张,不能卖出1001张票 - 使用**异步削峰+排队机制**,解决吞吐量问题,实现最短时间内给用户反馈,1000请求告知票没有了,1000请求告知排队中 - 使用**分布式事务**,保证数据最终一致性,不能库存减少了,票却没打出来。 ## 架构图 ![架构图.png](.\image\架构图.png) ## 典型高并发&高性能场景 ![典型高并发&高性能场景.png](.\image\典型高并发&高性能场景.png) ## 新版+主流技术 ![新版+主流技术.png](.\image\新版+主流技术.png) ## 一、启动train,vm虚拟机后,进入打开 ~/start.sh,按照说内容,启动中间件 ## 二、启动各个微服务和前端 ## 三、压力测试步骤: 1、执行如下SQL,清空每日数据: `1. train_business表 truncate table daily_train; truncate table daily_train_station; truncate table daily_train_carriage; truncate table daily_train_seat; truncate table daily_train_ticket; truncate table confirm_order; `2. train_member表 truncate table ticket; 2、进入管理后台(admin-web-业务管理-每日车次-手动生成车次信息),生成指定日期的车次数据,进入(admin-web-业务管理-令牌余量),修改令牌数到100万+ 3、复制daily-train-ticket表中的id;进入jmeter,打开项目根目录中的train.jmx文件(1s,100个线程,无限循环);将购票结构的dailyTrainTicketId,更新为前面复制的id;点击两个扫把图标,清空全部记录;再点击绿色三角图标启动压测,然后观察购票接口中的聚合报告-吞吐量,到达一分钟后;点击STOP图标,停止压测 4、压测基于本机本地运行,新旧代码压测结果对比,如下: 压测1分钟(吞吐量): 优化后: 压力测试 - 吞吐量:702/s, 平均响应时间:140ms,异常数:0.25% - git:20.7 使用异步线程代替RocketMQ(9f6bea2eeba29577a2d965f915367ef85393b8c4) ![](.\image\20.7 使用异步线程代替RocketMQ.png) 压力测试 - 吞吐量:607/s, 平均响应时间:162ms,异常数:0% - git:19.12 前端增加轮询购票结果功能,根据结果提示终态或排队人数(86d0db2a2d3c44630263ee9e92877647ba188928) ![](.\image\19.12 前端增加轮询购票结果功能,根据结果提示终态或排队人数.png) 优化前: 压力测试 - 吞吐量:46.2/s, 平均响应时间:2030ms,异常数:6.93% - git:13.5 解决IDEA自动从17变成8的问题(dd97ae795be00e69506b19c030e115e81580bec3) ![](.\image\13.5 解决IDEA自动从17变成8的问题.png) 702 / 46 = 15,也就是说优化后的吞吐量是优化前的**15倍**!!! 压测1分钟(并发数),要求响应是将不超过2s: 优化后,最终测得并发数为1500/s: 压力测试 - 吞吐量:739/s, 平均响应时间:1954ms,异常数:0.05% - git:20.7 使用异步线程代替RocketMQ(9f6bea2eeba29577a2d965f915367ef85393b8c4) ![](.\image\20.7 使用异步线程代替RocketMQ-2s.png) 优化后,最终测得并发数为1300/s: 压力测试 - 吞吐量:639/s, 平均响应时间:1951ms,异常数:0.06% - git:19.12 前端增加轮询购票结果功能,根据结果提示终态或排队人数(86d0db2a2d3c44630263ee9e92877647ba188928) ![](.\image\19.12 前端增加轮询购票结果功能,根据结果提示终态或排队人数-2s.png) 优化前,最终测得并发数为100/s: 压力测试 - 吞吐量:46.6/s, 平均响应时间:2026ms,异常数:5.32% - git:13.5 解决IDEA自动从17变成8的问题(dd97ae795be00e69506b19c030e115e81580bec3) ![](.\image\13.5 解决IDEA自动从17变成8的问题-2s.png) 1500 / 100 = 15,也就是说优化后的并发数是优化前的**15倍**!!! (PS:记得注释掉,ConfirmOrderService->sell()方法中的 为方便演示排队的200毫秒延时代码)