在设计架构前,需先明确 12306 的三大核心矛盾,这是所有技术方案的出发点:
1. 高并发:“潮汐式流量” 冲击 查询远大于售票:余票查询请求量是实际售票量的 1000 倍以上(用户反复刷新 “捡漏”),春运高峰时段单车次每秒查询超 1000 次,直接查数据库会导致 “库崩”; 售票峰值集中:早 8 点、12 点放票时,短时间内(10 分钟)集中爆发购票请求,需承受 “每秒数千次写操作”(票池扣减、订单创建),且不能出现响应超时。2. 强一致性:“票池零误差” 底线 绝对不超售:同一座位不能卖给两个用户,即使在分布式环境下(多服务节点同时扣减库存),也需保证 “库存扣减原子性”; 退票实时释放:用户退票后,库存需立即回补到票池,供其他用户抢购,避免 “票已退但余票不更新” 的资源浪费。展开剩余94%3. 高可用:“零宕机” 民生要求 核心功能不中断:购票、退票、改签是民生服务,即使某服务节点故障,也需通过 “集群容错” 确保业务连续; 数据不丢失:用户订单、支付记录、票池状态需永久存储,即使硬件故障(如数据库服务器宕机),也需能快速恢复数据。二、技术选型:SpringBoot3 微服务生态的 “适配性”12306 的架构设计并非 “技术堆砌”,而是 “业务痛点与技术特性的精准匹配”。选择 SpringBoot3 + 微服务生态,核心在于以下四大优势:
1. SpringBoot3:微服务开发的 “效率引擎” 原生支持微服务组件:SpringBoot3 对 Spring Cloud Alibaba(Nacos、Sentinel、Seata)、Spring Cloud Gateway 等微服务组件有 “零配置” 级兼容,无需手动整合依赖,开发效率提升 40%; 性能优化适配高并发:相比 SpringBoot2,SpringBoot3 支持 JDK17 + 的 AOT( Ahead-of-Time)编译,服务启动时间缩短 50%,内存占用降低 30%,更适合高并发场景下的 “快速扩容”(如春运前新增服务节点); 异步编程简化:通过@Async注解 + CompletableFuture,可轻松实现 “接口异步化”(如余票查询时异步加载用户常用联系人),提升接口吞吐量,避免同步阻塞导致的 “请求堆积”。2. 微服务拆分:“分而治之” 解耦复杂业务按 “业务域 + 职责单一” 原则,将 12306 拆分为 6 大核心微服务,每个服务独立部署、扩容,避免 “一荣俱荣、一损俱损”:
服务名称
核心职责
解决的痛点
用户服务(User)
用户登录、身份认证、常用联系人管理
解耦用户信息与购票逻辑,支持独立扩容
票池服务(TicketPool)
车次管理、库存维护(扣减 / 回补)、票价计算
聚焦票池一致性,避免超售、漏售
余票查询服务(TicketQuery)
余票实时查询、车次筛选(日期 / 席别)
承接 90% 查询流量,减轻票池服务压力
订单服务(Order)深金优配
订单创建、支付回调、退票 / 改签处理
解耦订单流程与库存逻辑,支持订单状态机管理
支付服务(Payment)
支付渠道对接(支付宝 / 微信)、退款处理
隔离支付风险,避免支付故障影响购票流程
通知服务(Notice)
短信 / APP 推送(订单通知、退票提醒)
异步通知用户,避免阻塞核心业务
3. 关键中间件:支撑高并发与一致性 Nacos:分布式配置中心 + 服务注册发现,统一管理各服务配置(如限流阈值、数据库连接池),支持动态更新(无需重启服务);同时实现服务间 “无感知调用”,故障节点自动下线; Redis 集群:承担 “热点数据缓存”(余票、用户会话)、“分布式锁”(票池扣减防超售)、“计数器”(车次查询量统计),单 Redis 集群可支撑每秒 10 万 + 读写请求; RocketMQ:消息队列解耦服务依赖(如订单创建后发消息给票池服务扣减库存),同时实现 “异步通信”(如订单支付后发消息给通知服务),避免服务间直接调用导致的 “故障扩散”; Seata:分布式事务框架,解决 “跨服务数据一致性” 问题(如订单创建 + 票池扣减需原子性,要么都成功,要么都失败); Sharding-JDBC:分库分表中间件,解决 “数据量爆炸” 问题(12306 年订单量超 10 亿条,单库单表无法存储),按 “车次 ID 哈希” 分表存储票池数据,按 “用户 ID 哈希” 分表存储订单数据。三、核心架构分层:从 “接入” 到 “数据” 的全链路设计12306 的架构按 “流量流向” 分为五层,每一层都有明确的 “防护与优化” 职责,形成 “层层拦截、层层优化” 的高可用体系:
1. 接入层:“流量过滤” 第一道防线接入层的核心是 “拦截无效流量、减轻后端压力”,对应 12306 的 “验证码限流、CDN 缓存” 策略:
CDN 静态资源缓存:将 “车次列表页、用户登录页” 等静态资源(JS、CSS、图片)缓存到全国 CDN 节点,用户访问时直接从就近 CDN 加载,避免请求穿透到核心服务,静态资源加载速度提升 80%; 限流防刷:通过 “验证码 + 令牌桶算法” 拦截恶意请求: 普通用户:每 10 秒可发起 1 次余票查询,超出则要求输入验证码; 疑似爬虫:连续 10 次查询无购票行为,临时封禁 IP(1 小时); 技术实现:基于 Sentinel 配置限流规则(按 IP / 用户 ID 维度),触发限流时返回 “请稍后重试”,避免恶意请求压垮后端。2. 网关层:“服务入口” 统一管控网关层采用 Spring Cloud Gateway,是微服务的 “统一入口”,承担 “路由转发、鉴权、熔断、监控” 四大职责:
动态路由:根据请求 URL 匹配对应微服务(如/api/ticket/query转发到余票查询服务,/api/order/create转发到订单服务),路由规则存储在 Nacos,支持动态调整(如临时下线某服务时,路由自动转发到备用节点); 统一鉴权:用户所有请求需携带 JWT 令牌,网关验证令牌有效性(是否过期、权限是否匹配),无效请求直接拦截,避免非法访问(如未登录用户调用购票接口); 熔断降级:当某服务(如余票查询服务)响应超时率超 50% 时,网关自动熔断该服务,返回 “缓存的余票数据” 或 “系统繁忙” 提示,避免故障扩散到订单、票池等核心服务; 流量监控:网关实时统计各服务的请求量、响应时间、错误率,数据同步到 Prometheus+Grafana,运维人员可直观看到 “哪条线路压力大”(如北京→上海车次查询量激增),及时扩容。3. 业务服务层:“核心逻辑” 精准落地业务服务层是 12306 的 “大脑”,重点拆解票池、订单、余票查询三大核心服务的设计逻辑:
(1)票池服务:“零超售” 的核心保障票池服务是 12306 的 “命脉”,需解决 “分布式环境下库存一致性” 问题,核心设计有三大关键点:
票池数据结构:按 “车次 - 席别” 分层存储票池数据分为 “车次基础信息”(如车次号、出发 / 到达时间、总席别数)和 “库存明细”(如某车次二等座剩余 20 张,对应座位号 A1、A2...),存储在分库分表后的 MySQL 集群(按车次 ID 哈希分表),确保 “热门车次数据分散存储,避免单表压力过大”;
库存扣减:“预扣减 + 分布式锁” 防超售用户点击 “购票” 时,票池服务执行两步操作:
① 先通过 Redis Redisson 的分布式锁(锁 Key 为 “车次 ID - 席别”,如train_12345_second)锁定该车次的库存深金优配,避免多用户同时扣减;
② 预扣减库存(MySQL 中库存数 - 1,状态标记为 “锁定”),锁定时间 15 分钟(用户支付超时自动释放);
③ 若用户支付成功,将库存状态改为 “已售”;若支付超时 / 取消,通过 RocketMQ 事务消息回补库存(确保即使服务宕机,库存也能恢复);
退票回补:“实时 + 最终一致”用户退票时,票池服务先修改库存状态为 “可用”(MySQL+Redis 同步更新),确保其他用户能立即查询到 “新释放的余票”;同时发消息到 RocketMQ,异步同步到余票查询服务的缓存,避免 “退票后余票不更新” 的问题。
(2)余票查询服务:“高并发查询” 的性能优化余票查询服务承接 90% 的请求量,核心是 “减轻数据库压力,提升查询速度”,设计思路围绕 “缓存优先”:
多级缓存:本地缓存 + Caffeine+Redis 集群① 本地缓存(Caffeine):每个服务节点缓存 “热门车次余票”(如近 1 小时查询量超 10 万次的车次),查询时先查本地缓存,命中则直接返回,响应时间 < 10ms;
② Redis 集群:缓存全量车次余票(非热门车次),本地缓存未命中时查 Redis,响应时间 < 50ms;
③ MySQL:仅当 Redis 缓存失效(如车次信息更新)时才查数据库,数据库查询量减少 99%;
缓存预热与更新:避免 “缓存穿透 / 击穿”① 缓存预热:放票前 1 小时(如早 7 点),通过定时任务(Spring Scheduled)将当日热门车次余票加载到 Redis 和本地缓存,避免 “放票瞬间大量请求穿透到数据库”;
② 缓存更新:票池服务库存变化时(购票 / 退票),通过 RocketMQ 消息通知余票查询服务,实时更新 Redis 和本地缓存,确保 “余票数据与票池一致”;
③ 防穿透:用布隆过滤器(Bloom Filter)存储 “已存在的车次 ID”,不存在的车次查询(如伪造车次号)直接拦截,避免请求穿透到数据库;
④ 防击穿:热门车次缓存过期时,用互斥锁(Redis SET NX)确保 “只有一个请求去查数据库,其他请求等待缓存更新”,避免 “缓存过期瞬间大量请求压垮数据库”。
(3)订单服务:“状态流转” 的严谨管控订单服务需处理 “创建 - 支付 - 完成 / 退票 / 改签” 的全流程,核心是 “状态机管理 + 分布式事务”:
订单状态机:避免状态混乱定义订单的 5 种核心状态:待支付(PENDING_PAY)→已支付(PAID)→已出票(TICKETED)→已完成(COMPLETED),以及异常状态已取消(CANCELLED)、已退票(REFUNDED);
状态流转严格遵循 “预设规则”(如 “待支付” 只能流转到 “已支付” 或 “已取消”,不能直接到 “已完成”),通过 Spring StateMachine 实现状态机管理,避免 “状态跳变”(如用户未支付却显示 “已出票”);
分布式事务:订单创建与库存扣减原子性用户购票时,需同时调用 “订单服务创建订单” 和 “票池服务扣减库存”,两者必须原子性(要么都成功,要么都失败),采用 Seata TCC 模式实现:
① Try 阶段:订单服务创建 “预订单”(状态为 “待支付”),票池服务预扣减库存(状态为 “锁定”);
② Confirm 阶段:若支付成功,订单服务将 “预订单” 改为 “已支付”,票池服务将 “锁定库存” 改为 “已售”;
③ Cancel 阶段:若支付失败 / 超时,订单服务删除 “预订单”,票池服务回补库存;
TCC 模式相比 2PC 更适合高并发场景(无全局锁,性能更高),确保 “订单与库存数据一致”。
4. 数据层:“海量数据” 的存储与高可用12306 的数据量极大(年订单 10 亿 +、车次数据百万 +),数据层采用 “分库分表 + 主从复制 + 冷热分离” 设计:
分库分表:Sharding-JDBC 支撑海量数据 票池数据:按 “车次 ID 哈希” 分表,如 100 个分表,车次 ID=12345 的数据存储在第123450=45张表,避免单表数据量超千万导致查询变慢; 订单数据:按 “用户 ID 哈希” 分库,同时按 “订单创建时间” 分表(如每月一张表),既支持 “按用户查询历史订单”,也支持 “按时间统计订单量”; MySQL 主从复制:读写分离减压力每个分库采用 “1 主 2 从” 架构:主库处理写操作(如库存扣减、订单创建),从库处理读操作(如查询历史订单、统计车次售票量),通过 Sharding-JDBC 自动实现 “写走主库,读走从库”,主库压力降低 70%;
主从同步采用 MySQL MGR(Group Replication),同步延迟 < 100ms,确保从库数据实时性;若主库宕机,MGR 自动选举新主,业务中断时间 < 30s;
冷热数据分离:降低存储成本 热数据(近 3 个月订单、当日车次数据):存储在 MySQL 集群,确保 “查询快、修改灵”; 冷数据(3 个月前订单、历史车次数据):迁移到低成本存储(如 HDFS+Hive),查询时通过 “数据联邦”(Sharding-JDBC 关联 MySQL 和 Hive)实现 “冷热数据统一查询”,存储成本降低 60%。5. 中间件层:“解耦与容错” 的支撑中间件层是微服务的 “基础设施”,确保服务间 “通信可靠、数据不丢、故障可控”:
RocketMQ:异步解耦与消息可靠投递服务间通信不直接调用,而是通过 RocketMQ 发送消息:如订单创建后发order_created消息,票池服务消费消息扣减库存,通知服务消费消息发送短信;
采用 “事务消息” 确保 “消息不丢”(如订单创建成功才发消息,失败则回滚消息),“重试机制”(消费失败自动重试 3 次,仍失败则进入死信队列人工处理);
Redis 集群:高可用缓存与分布式锁Redis 采用 “3 主 3 从” 集群架构,主节点负责读写,从节点同步数据,哨兵(Sentinel)监控主节点状态,主节点宕机时自动切换从节点为主,确保 Redis 服务不中断;
分布式锁采用 Redisson 的RLock,支持 “可重入、自动续期”(避免锁超时导致超售),满足票池扣减的 “互斥需求”;
Seata:分布式事务一致性保障Seata 采用 “AT 模式”(适合简单业务)和 “TCC 模式”(适合复杂业务),12306 的订单 - 票池交互用 TCC,支付 - 退款交互用 AT,确保 “跨服务数据一致”;
Seata Server 部署集群,避免单点故障,事务日志存储在 MySQL,即使 Seata Server 宕机,重启后仍能恢复未完成的事务。
四、高性能优化:从 “能用” 到 “春运级可用” 的关键12306 的高性能并非 “单一技术优化”,而是 “全链路协同优化”,重点有五大手段:
1. 读写分离 + 缓存穿透:减轻数据库压力 余票查询 99% 走缓存(本地缓存 + Redis),仅 1% 走数据库; 订单查询 80% 走 MySQL 从库,20%(实时订单)走主库; 布隆过滤器拦截 “无效车次查询”,数据库穿透率 < 0.1%。2. 异步化 + 并行化:提升接口吞吐量 接口异步化:余票查询时,异步加载 “用户常用联系人”“车次晚点信息”,主流程仅返回余票数据,接口响应时间从 300ms 降至 50ms; 任务并行化:订单创建时,并行调用 “用户服务校验身份”“票池服务预扣减库存”“支付服务生成支付链接”,任务执行时间从 500ms 降至 200ms。3. 服务扩容:“弹性应对” 峰值流量 水平扩容:基于 K8s 实现 “弹性伸缩”,根据 CPU 利用率(如超 70%)自动新增服务节点,春运高峰时可从日常 100 个节点扩容到 1000 个节点; 垂直拆分:将 “余票查询服务” 独立部署在更多节点(占总节点数的 60%),因为其请求量最大,避免 “一个服务占用过多资源”。4. JVM 调优:释放 Java 性能潜力 JDK 版本:采用 JDK17,相比 JDK8 性能提升 20%,支持 AOT 编译; 堆内存配置:服务节点堆内存设为 16G(-Xms16g -Xmx16g),避免频繁 GC; GC 算法:采用 G1 GC(-XX:+UseG1GC),适合大堆内存,GC 停顿时间控制在 100ms 以内,避免 GC 导致的 “请求超时”。5. 业务优化:从 “技术” 到 “业务” 的协同 分时段售票:将热门车次的放票时间分散到早 8 点、10 点、12 点,避免 “单时间点流量爆炸”; 排队机制:放票瞬间若请求超阈值,启用 “排队系统”(如 “您排在 1234 位,预计等待 5 分钟”),将 “集中流量” 转化为 “匀速流量”; 余票缓存粒度:余票查询按 “车次 - 席别” 缓存(如某车次二等座剩余 20 张),而非 “单个座位号”,减少缓存更新频率(如扣减 1 张二等座,仅需更新 “剩余 20→19”,无需修改单个座位缓存)。五、高可用保障:“零宕机” 的多层防护12306 作为民生服务,高可用是 “底线”,通过 “集群容错、灾备、监控告警” 三层防护实现:
1. 集群容错:避免单点故障 所有服务(网关、业务服务、中间件)均集群部署,无单点; 服务调用采用 “负载均衡”(Spring Cloud LoadBalancer),请求均匀分发到各节点,避免单节点压力过大; 熔断降级(Resilience4j):某服务节点响应超时率超 50% 时,自动熔断该节点,请求转发到其他健康节点,故障恢复后自动恢复调用。2. 灾备设计:“异地多活” 抗风险 采用 “两地三中心” 架构:在北京、上海部署生产中心,在广州部署灾备中心; 日常状态:北京、上海中心同时提供服务(负载分担),数据实时同步(通过 MySQL MGR 跨地域同步); 故障应对:若北京中心因自然灾害(如地震)瘫痪,上海中心自动承接 100% 流量;若上海中心也故障,广州灾备中心在 1 小时内接管业务,数据零丢失。3. 监控告警:“提前发现” 故障 全链路监控:采用 SkyWalking 实现 “服务调用链追踪”,可定位 “哪次请求在哪个服务节点耗时过长”(如余票查询服务在节点 A 响应时间超 500ms); 指标监控:Prometheus+Grafana 监控各服务的 CPU、内存、接口响应时间、错误率,设置阈值告警(如接口错误率超 1%、CPU 利用率超 80%); 告警通知:告警信息通过 “钉钉 + 短信 + 电话” 三级通知,10 分钟内未响应则升级通知(如从工程师到技术总监),确保故障 “早发现、早解决”。六、12306 架构的核心启示基于 SpringBoot3 的 12306 微服务架构,本质是 “业务驱动技术,技术支撑业务” 的典范,其核心启示有三点:
“分” 是高并发的核心思路:通过微服务拆分(分业务)、分库分表(分数据)、读写分离(分压力),将 “大问题” 拆成 “小问题”,每个小问题单独解决,避免 “一拥而上” 导致的系统崩溃; “缓存” 是高查询的关键:余票查询 99% 走缓存,通过多级缓存、缓存预热、缓存更新,既提升查询速度,又减轻数据库压力,这是 “读多写少” 场景的通用优化方案; “弹性” 是高可用的保障:通过集群容错、弹性扩容、灾备设计,让系统 “能抗住峰值、能应对故障”,而非追求 “绝对无故障”,这是分布式系统的务实设计思路。对于开发者而言,12306 的架构并非 “遥不可及”——SpringBoot3 微服务生态降低了分布式系统的开发门槛,关键在于 “理解业务痛点,选择合适的技术方案”。无论是开发电商秒杀系统、票务系统,还是其他高并发系统,都可借鉴 “分而治之、缓存优先、弹性容错” 的思路深金优配,让技术真正服务于业务需求。
发布于:河北省恒财网配资提示:文章来自网络,不代表本站观点。