1. 项目背景与核心需求
健身房管理系统是当前健身行业数字化转型的核心工具。随着全民健身意识提升,传统手工登记会员信息、电话预约课程的方式已经无法满足现代健身房运营需求。我们团队开发的这套系统基于SpringBoot框架,主要解决三个核心业务场景:
- 场地管理:实时显示各区域(泳池、器械区、团操房)使用状态,支持分时段预约
- 教练调度:可视化展示教练排班表,会员可查看教练资质和评价
- 课程预约:团课/私教课在线预约、取消、改签一体化流程
提示:系统设计时特别考虑了高峰期并发问题,比如晚上7-9点的课程预约高峰,采用Redis缓存热门课程余量。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选型
mermaid复制graph TD
A[前端] -->|Vue.js| B(SpringBoot)
B -->|MyBatis| C[MySQL]
B -->|Redis| D[缓存层]
B -->|RabbitMQ| E[消息队列]
实际开发中我们调整了技术方案:
- 前端:改用Thymeleaf模板引擎,减少前后端分离带来的部署复杂度
- 持久层:MyBatis-Plus + 多数据源配置(主库写,从库读)
- 缓存:Redis五种数据结构应用场景:
- String:存储课程剩余名额
- Hash:教练详细信息
- ZSet:热门课程排行榜
- BitMap:会员签到记录
- Geo:附近健身房搜索
2.2 核心业务表设计
主要数据库表关系如下:
| 表名 | 关键字段 | 索引优化点 |
|---|---|---|
| tb_member | id, phone(唯一), level, points | phone字段唯一索引 |
| tb_coach | id, name, tags, certification | 组合索引(tags+avg_score) |
| tb_course | id, type, coach_id, max_capacity | 联合索引(type+time_slot) |
| tb_booking | order_no, member_id, status | 覆盖索引(order_no+status) |
踩坑记录:最初没给tb_booking的status字段加索引,导致高峰期查询性能下降70%
3. 关键业务实现细节
3.1 预约服务的分布式锁实现
课程秒杀场景下的核心代码:
java复制public boolean bookCourse(Long courseId, Long memberId) {
String lockKey = "lock:course:" + courseId;
String token = UUID.randomUUID().toString();
try {
// 获取分布式锁(SETNX+过期时间)
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, token, 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 1. 检查课程余量
// 2. 扣减库存
// 3. 创建订单
return executeBooking(courseId, memberId);
}
} finally {
// Lua脚本保证原子性解锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) else return 0 end";
redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(lockKey),
token);
}
return false;
}
3.2 教练时间片算法
教练排班的核心逻辑:
java复制public List<TimeSlot> generateTimeSlots(Coach coach, LocalDate date) {
// 基础时间片(30分钟为单位)
List<TimeSlot> slots = createBaseSlots(date);
// 排除已有预约时段
removeBookedSlots(slots, coach.getId());
// 排除教练休息时间
applyRestRules(slots, coach.getWorkRule());
// 动态调整热门时段
if (isWeekend(date)) {
adjustHotSlots(slots, "19:00", "21:00");
}
return slots;
}
4. 性能优化实战
4.1 查询优化方案对比
| 场景 | 原始方案 | 优化方案 | QPS提升 |
|---|---|---|---|
| 课程列表查询 | 全表扫描+Java过滤 | ES全文检索+聚合桶 | 300% |
| 教练详情 | 5次独立查询 | 一次查询+Redis缓存 | 150% |
| 会员预约历史 | 分页查询全量数据 | 游标分页+覆盖索引 | 200% |
4.2 JVM参数调优记录
生产环境最终配置:
bash复制java -jar \
-Xms2048m -Xmx2048m \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:ParallelGCThreads=4 \
-XX:ConcGCThreads=2 \
-Dspring.profiles.active=prod \
app.jar
5. 安全防护措施
5.1 预约业务防刷策略
- 图形验证码:预约前必须验证(采用Kaptcha)
- 限流规则:
- 单个IP:50次/分钟
- 会员账号:10次/小时
- 行为分析:识别异常预约模式(如固定间隔秒级请求)
5.2 敏感数据保护
java复制// 会员手机号脱敏处理
public String maskPhone(String phone) {
if (StringUtils.isEmpty(phone)) return "";
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
6. 部署架构
最终采用的K8s部署方案:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: gym-booking
spec:
replicas: 3
selector:
matchLabels:
app: gym-booking
template:
spec:
containers:
- name: app
image: registry.example.com/gym:1.2.0
envFrom:
- configMapRef:
name: gym-config
resources:
limits:
cpu: "2"
memory: 2Gi
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: gym-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: gym-booking
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
7. 监控告警体系
Prometheus监控关键指标:
-
业务指标:
- 每分钟预约量
- 课程取消率
- 教练被预约率Top10
-
系统指标:
- JVM GC次数
- Redis命中率
- 数据库连接池使用率
告警规则示例:
yaml复制- alert: HighCancelRate
expr: rate(booking_cancel_total[5m]) > 0.3
for: 10m
labels:
severity: warning
annotations:
summary: "高课程取消率 (instance {{ $labels.instance }})"
description: "5分钟内取消率超过30%"
8. 典型问题排查实录
8.1 幽灵预约问题
现象:后台显示课程已约满,但仍有会员能预约成功
排查过程:
- 检查Redis库存缓存:无异常
- 追踪日志发现:两个请求同时通过余量检查
- 确认问题:数据库乐观锁版本号未正确回写
解决方案:
java复制@Transactional
public boolean bookCourse(Long courseId) {
Course course = courseMapper.selectForUpdate(courseId); // 改为悲观锁
if (course.getRemain() > 0) {
course.setRemain(course.getRemain() - 1);
return courseMapper.updateById(course) > 0;
}
return false;
}
8.2 缓存雪崩应对
现象:凌晨批量更新课程时,Redis集群响应超时
优化方案:
- 缓存更新改为增量更新
- 添加本地缓存作为二级缓存
- 对批量操作实施熔断机制
最终采用的缓存架构:
code复制请求 → 本地缓存 → Redis集群 → 数据库
↑ ↑
Fallback 双写一致
9. 扩展功能设计
9.1 智能推荐系统
基于会员行为的推荐逻辑:
python复制# 协同过滤算法简化实现
def recommend_courses(member_id):
# 获取相似会员
similar_members = find_similar_users(member_id)
# 聚合推荐课程
courses = aggregate_courses(similar_members)
# 排除已预约课程
return filter_booked_courses(member_id, courses)
9.2 微信小程序集成
关键对接点:
- 微信登录流程改造
- 模板消息推送预约提醒
- 小程序码签到功能
接口安全增强:
- 签名验证
- 请求时效性检查
- 敏感接口频率限制
10. 项目演进路线
已完成里程碑:
- v1.0:基础预约功能(2023.03)
- v1.5:引入Redis缓存(2023.06)
- v2.0:微服务化改造(2023.09)
未来规划:
- 引入Elasticsearch实现智能搜索
- 增加VR场馆预览功能
- 开发会员健康数据分析模块
实际开发中我们发现,约30%的需求变更来自于健身房运营人员的实际反馈,因此建立了每月需求收集机制,持续优化系统功能。
