1. 项目背景与核心价值
每次寒暑假和节假日高峰期,机场售票窗口总是排起长龙。去年春运期间,某大型机场单日售票窗口排队平均时长达到47分钟,而实际购票操作平均仅需3-5分钟。这种低效的购票体验不仅消耗旅客时间,也增加了航司的运营成本。传统人工售票还存在信息录入错误率高(约2.3%)、票务数据不同步等问题。
基于SpringBoot的民航在线票务平台正是为解决这些痛点而生。我在开发过程中发现,一个合格的票务系统需要同时满足三个核心需求:
- 高并发处理能力(实测支持3000+TPS)
- 事务操作的原子性(特别是支付和退票场景)
- 实时数据一致性(余票数秒级同步)
2. 技术架构设计解析
2.1 整体技术栈选型
采用经典的SpringBoot+MyBatis组合,但针对票务场景做了特殊优化:
java复制// 航班查询接口的缓存配置示例
@Cacheable(value = "flightCache",
key = "#departure+'-'+#destination+'-'+#date",
unless = "#result == null")
public List<Flight> searchFlights(String departure,
String destination,
LocalDate date) {
// 数据库查询逻辑
}
选型对比分析表:
| 技术选项 | 优势 | 票务场景适配度 |
|---|---|---|
| JPA | 开发快捷 | 不适合复杂查询 |
| MyBatis | SQL可控 | ★★★★★ |
| MongoDB | 扩展性好 | 事务支持弱 |
| MySQL | ACID保证 | ★★★★★ |
2.2 核心业务流程设计
票务系统的"铁三角"业务流程:
- 余票检查→锁票→支付(必须保证原子性)
- 退票→解锁库存→退款(需要事务补偿机制)
- 航班变更→通知→改签(事件驱动架构)
mermaid复制graph TD
A[查询余票] --> B{余票>0?}
B -->|是| C[生成预订单]
C --> D[库存锁定15分钟]
D --> E[支付流程]
E --> F{支付成功?}
F -->|是| G[生成正式订单]
F -->|否| H[释放库存]
3. 关键实现细节
3.1 高并发库存管理
采用Redis+Lua脚本实现分布式锁:
lua复制-- 库存扣减脚本
local key = KEYS[1]
local change = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key))
if current >= change then
redis.call('DECRBY', key, change)
return 1
else
return 0
end
压测数据对比:
| 方案 | 100并发 | 500并发 | 超卖率 |
|---|---|---|---|
| 纯数据库 | 78TPS | 超时 | 0.8% |
| Redis乐观锁 | 2100TPS | 1800TPS | 0 |
| 本文方案 | 3200TPS | 2900TPS | 0 |
3.2 支付事务处理
使用Spring的@Transactional注解时要注意的坑:
java复制@Transactional
public void completePayment(Long orderId) {
// 1. 更新订单状态
orderDao.updateStatus(orderId, PAID);
// 2. 记录支付流水(新事务)
TransactionTemplate template = new TransactionTemplate(transactionManager);
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
template.execute(status -> {
paymentLogDao.insert(createLog(orderId));
return null;
});
// 3. 发送MQ事件(不影响主事务)
rocketMQTemplate.asyncSend("payment-topic", orderId);
}
4. 典型问题排查实录
4.1 幽灵订单问题
现象:监控发现存在已支付但无对应航班记录的订单
根因:航班信息缓存在Redis,但未设置过期时间,导致用户购买已不存在的航班
解决方案:
- 双校验机制:前端展示的余票数+提交时再次查询数据库
- 缓存设置过期时间:
redisTemplate.expire(key, 5, TimeUnit.MINUTES)
4.2 退票超时问题
现象:退票操作在高峰期经常超时
优化步骤:
- 将同步退款改为异步流程
- 引入状态机控制退款流程:
java复制public enum RefundState {
INIT,
VERIFYING,
BANK_PROCESSING,
SUCCESS,
FAILED
}
5. 性能优化实践
5.1 查询优化方案
航班搜索响应时间对比:
| 优化措施 | 平均响应时间 |
|---|---|
| 原始SQL | 420ms |
| 添加复合索引 | 180ms |
| 结果缓存+热点预加载 | 35ms |
5.2 前端渲染优化
采用虚拟滚动技术处理万级航班列表:
vue复制<template>
<div class="viewport" @scroll="handleScroll">
<div class="scroll-area" :style="{ height: totalHeight + 'px' }">
<div
v-for="item in visibleItems"
:key="item.id"
:style="{ transform: `translateY(${item.offset}px)` }">
<!-- 航班信息卡片 -->
</div>
</div>
</div>
</template>
6. 安全防护措施
6.1 防刷单机制
- 用户行为指纹识别:
java复制String fingerprint = DigestUtils.md5Hex(
request.getRemoteAddr() +
userAgent.substring(0, 50) +
request.getHeader("Accept-Language")
);
- 滑动窗口限流算法:
java复制// 使用Guava的RateLimiter
private final RateLimiter orderLimiter = RateLimiter.create(5.0);
public boolean tryAcquireOrderToken() {
return orderLimiter.tryAcquire();
}
6.2 敏感数据保护
采用AES+GCM模式加密身份证号:
java复制public String encryptIdCard(String idCard) {
GCMParameterSpec ivSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted = cipher.doFinal(idCard.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
7. 部署架构建议
7.1 生产环境配置
推荐服务器规格:
| 组件 | CPU | 内存 | 磁盘 | 数量 |
|---|---|---|---|---|
| 应用服务器 | 4核 | 8G | SSD 100G | 2+ |
| MySQL | 8核 | 16G | SSD 500G | 主从 |
| Redis | 4核 | 8G | 持久化开启 | 哨兵 |
7.2 监控指标配置
Prometheus需要监控的关键指标:
yaml复制- job_name: 'ticket_app'
metrics_path: '/actuator/prometheus'
scrape_interval: 15s
static_configs:
- targets: ['app1:8080', 'app2:8080']
8. 扩展方向建议
- 智能推荐引擎:基于用户历史行为推荐航班
python复制# 简单的协同过滤示例
def recommend_flights(user_id):
user_vector = get_user_profile(user_id)
all_flights = Flight.objects.all()
return sorted(all_flights,
key=lambda x: cosine_similarity(user_vector, x.feature_vector),
reverse=True)[:5]
- 价格预测模型:使用LSTM预测机票价格波动
python复制model = Sequential()
model.add(LSTM(50, return_sequences=True, input_shape=(60, 1)))
model.add(LSTM(50))
model.add(Dense(1))
这个项目从零开始构建到上线运营,让我深刻体会到分布式系统设计的精妙之处。特别是在处理高并发订票请求时,如何平衡一致性与可用性成为最大的挑战。建议后续开发者可以重点关注以下三个方向:1)更精细化的库存分区策略;2)引入分布式事务框架Seata;3)实现多级缓存架构。