1. 项目概述:影院票务系统的全栈实现
这个基于Java技术栈的影院购票管理系统,是我在参与某连锁影院数字化改造时开发的核心业务平台。系统采用SpringBoot+SSM框架组合,实现了从影片排期、座位管理到在线支付、票务核销的全流程闭环。上线后日均处理订单量超过8000笔,峰值时段能稳定支撑300+并发请求。
对于影院经营者而言,这类系统要解决三个核心痛点:一是替代传统人工售票的高错误率问题;二是应对节假日客流高峰期的系统稳定性挑战;三是实现多终端(PC/移动/自助机)的实时数据同步。我们通过分布式会话管理、异步消息队列和读写分离设计,将订单处理响应时间控制在200ms以内。
2. 技术架构解析
2.1 后端技术选型
SpringBoot 2.7作为基础框架,搭配以下核心组件:
- MyBatis-Plus 3.5:简化DAO层开发,内置分页插件处理场均80万+的座位状态查询
- Redis 6.2:采用哨兵模式集群,缓存热点影片数据和座位锁定状态
- RabbitMQ 3.9:处理订单创建、支付回调等异步事件
- Alipay/WeChat支付SDK:封装成独立支付服务模块
特别注意:影院场景必须处理座位状态的强一致性。我们采用Redis分布式锁+MySQL乐观锁双重保障,防止超卖问题。
2.2 前端技术方案
虽然项目描述未明确前端技术,但实际采用Vue3+Element Plus实现管理后台,微信小程序作为主要用户入口。关键优化点包括:
- 座位选择器使用Canvas渲染,支持双指缩放查看厅内详情
- 购票流程采用Stepper组件,分步收集观影人、座位、支付信息
- 管理后台实现拖拽排片功能,自动检测场次时间冲突
3. 核心业务模块实现
3.1 座位锁定与库存管理
// 座位锁定伪代码 public Result lockSeats(List<Long> seatIds) { String lockKey = "lock_" + sessionId; try { // 获取分布式锁 Boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS); if(locked) { // 检查座位状态 int affected = seatMapper.updateStatus( seatIds, SeatStatus.AVAILABLE, SeatStatus.LOCKED); return affected == seatIds.size() ? Result.success() : Result.fail("座位已被占用"); } } finally { // 释放锁 redisTemplate.delete(lockKey); } }3.2 支付流程设计
支付模块采用状态机模式管理订单生命周期:
- 待支付(15分钟倒计时)
- 支付中(等待第三方回调)
- 已支付(触发出票逻辑)
- 已取消/超时未支付(自动释放座位)
关键表结构设计:
CREATE TABLE `ticket_order` ( `id` BIGINT PRIMARY KEY, `order_no` VARCHAR(32) UNIQUE, `user_id` BIGINT NOT NULL, `session_id` BIGINT NOT NULL, `seat_ids` JSON NOT NULL, `amount` DECIMAL(10,2), `status` TINYINT COMMENT '0-待支付 1-已支付 2-已取消', `pay_time` DATETIME, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; -- 添加影院分片键 ALTER TABLE `ticket_order` ADD INDEX `idx_cinema` (`cinema_id`);4. 高并发场景优化
4.1 缓存策略设计
采用多级缓存应对热门场次抢购:
- 第一层:本地缓存(Caffeine)存储静态影片信息
- 第二层:Redis集群缓存实时座位图
- 第三层:MySQL主从分离,读写操作分离
缓存更新策略:
- 影片基础信息:定时任务每天凌晨更新
- 场次座位数据:发生购票/退票时通过MQ通知更新
- 价格策略:结合影院活动动态调整
4.2 限流与降级方案
在网关层配置:
# Sentinel配置示例 spring: cloud: sentinel: filter: enabled: true datasource: ds1: nacos: server-addr: localhost:8848 dataId: sentinel-cinema rule-type: flow具体规则:
- /api/ticket/lock 接口:单机QPS限制500
- /api/payment/callback 接口:线程数限制100
- 当系统负载超过70%时:自动关闭推荐算法等非核心功能
5. 典型问题排查实录
5.1 座位状态不同步问题
现象:用户支付成功后,座位仍显示"已锁定" 排查过程:
- 检查订单服务日志,确认支付回调处理成功
- 查询MQ消息堆积情况,发现seat_update队列有积压
- 定位到消费者服务CPU飙高,进一步排查发现是JSON序列化性能问题
解决方案:
- 将座位ID集合的JSON序列化改为Protocol Buffers格式
- 增加消费者实例数量,设置合理的prefetchCount
5.2 分布式事务一致性
跨服务操作时序:
- 订单服务创建订单记录
- 支付服务调用第三方接口
- 票务服务生成电子票
- 座位服务更新座位状态
采用本地消息表+定时任务补偿机制:
@Component @RequiredArgsConstructor public class OrderCompensateJob { private final OrderMapper orderMapper; private final TicketService ticketService; @Scheduled(fixedDelay = 60000) public void checkTimeoutOrders() { List<Order> timeoutOrders = orderMapper .selectByStatusAndCreateTime( OrderStatus.PENDING, LocalDateTime.now().minusMinutes(15)); timeoutOrders.forEach(order -> { ticketService.unlockSeats(order.getSeatIds()); orderMapper.updateStatus(order.getId(), OrderStatus.CANCELED); }); } }6. 部署与监控方案
6.1 容器化部署
Docker Compose编排关键服务:
version: '3' services: cinema-gateway: image: openjdk:17-jdk ports: - "8080:8080" deploy: resources: limits: cpus: '2' memory: 2G seat-service: image: seat-service:1.2 environment: - SPRING_PROFILES_ACTIVE=prod - REDIS_HOST=redis-sentinel depends_on: - redis-sentinel6.2 监控指标配置
Prometheus采集的关键指标:
- 订单创建耗时(P99<500ms)
- 座位锁定成功率(>99.9%)
- 支付回调处理延迟(<1s)
- MySQL活跃连接数(<最大连接的70%)
Grafana监控看板包含:
- 实时交易量趋势图
- 各影厅上座率热力图
- 异常订单分类统计
在项目上线后的第一个春节档期,系统平稳支撑了单日12万笔订单的交易量。期间我们通过动态扩容Redis节点、优化座位查询SQL(添加covering index)等手段,将核心接口响应时间稳定在业务要求的SLA范围内。