1. 项目概述:SpringBoot医院在线挂号系统开发实录
去年参与某三甲医院信息化改造时,我负责的在线挂号模块上线首日就承受了2.3万次并发访问。这个基于SpringBoot的挂号系统最终实现了98.7%的预约成功率,今天就把从架构设计到源码实现的完整经验分享给大家。
这类系统核心要解决三大矛盾:患者对挂号便捷性的需求与医院号源有限的矛盾、高并发访问与系统稳定性的矛盾、业务复杂度与开发效率的矛盾。SpringBoot的约定优于配置理念配合分布式架构,恰好能平衡这些需求。下面我会结合具体业务场景,拆解挂号系统的技术实现要点。
2. 系统架构设计解析
2.1 技术栈选型依据
选择SpringBoot2.7 + MyBatis-Plus + Redis的组合主要基于以下考量:
- 挂号业务存在明显的早高峰特征(每日7:00-9:00),Redis的读写分离能有效分担MySQL压力
- MyBatis-Plus的Lambda查询构建器可减少30%以上的DAO层代码量
- SpringBoot Actuator的健康检查机制对医院7×24小时服务至关重要
数据库表设计中,号源表(schedule)采用分库分表策略,按科室ID哈希分片。这里有个细节:将热门科室(如心血管内科)的号源数据单独存放在高性能SSD存储节点。
2.2 高并发场景应对方案
挂号业务最典型的秒杀场景需要特殊处理:
java复制// 使用Redis分布式锁防止超卖
public boolean lockRegistration(String lockKey, String requestId, int expireTime) {
return redisTemplate.opsForValue().setIfAbsent(
lockKey,
requestId,
expireTime,
TimeUnit.SECONDS
);
}
我们实测过的几种方案对比:
| 方案 | QPS上限 | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 纯数据库乐观锁 | 1200 | 低 | 小型医院 |
| Redis原子计数器 | 8500 | 中 | 中型医院 |
| Redis+Lua脚本 | 12000 | 高 | 三甲医院高峰期 |
| 本地缓存+异步队列 | 18000 | 极高 | 互联网医院平台 |
3. 核心业务模块实现
3.1 号源动态编排算法
医院排班是个复杂过程,需要考虑:
- 医生出诊规律(如每周二上午)
- 节假日调班
- 急诊绿色通道保留号
我们设计的动态规则引擎实现:
java复制public List<Schedule> generateSchedules(Doctor doctor, Date startDate, Date endDate) {
// 1. 获取医生基础排班规则
RuleTemplate template = ruleService.getTemplate(doctor.getRuleId());
// 2. 应用节假日特殊规则
HolidayRuleDecorator holidayRule = new HolidayRuleDecorator(template);
// 3. 生成可预约时间段
return holidayRule.generate(doctor, startDate, endDate);
}
3.2 支付超时自动解锁
挂号成功后15分钟内未支付自动释放号源:
java复制@Scheduled(cron = "0 */1 * * * ?")
public void releaseUnpaidOrders() {
List<Order> unpaidOrders = orderMapper.selectUnpaidOrders();
unpaidOrders.forEach(order -> {
if (System.currentTimeMillis() - order.getCreateTime() > 900000) {
redisTemplate.opsForValue().increment(
"schedule:" + order.getScheduleId(),
1
);
orderMapper.updateStatus(order.getId(), OrderStatus.CANCELLED);
}
});
}
4. 安全与合规设计要点
4.1 患者隐私保护
- 数据脱敏:就诊人身份证号显示为"110**********1234"
- 接口加密:采用AES+SM4混合加密方案
- 日志过滤:使用Logback的PatternFilter过滤敏感信息
4.2 防黄牛机制
我们实现了多维度风控策略:
- 设备指纹识别(同一设备1小时内最多预约3次)
- 行为分析(异常快速点击触发验证码)
- 信用分级(黑名单用户限制预约热门科室)
5. 性能优化实战记录
5.1 缓存策略优化
采用多级缓存架构:
- 本地Caffeine缓存(有效期5分钟)
- Redis集群缓存(有效期2小时)
- MySQL持久化存储
缓存更新策略对比:
| 策略 | 一致性 | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 定时刷新 | 弱 | 低 | 非核心数据 |
| 主动失效 | 强 | 中 | 号源状态 |
| 双写一致性 | 最强 | 高 | 患者基础信息 |
5.2 数据库连接池配置
根据压测结果优化的Druid配置:
properties复制# 高峰期配置(7:00-9:00)
spring.datasource.druid.initial-size=20
spring.datasource.druid.max-active=100
spring.datasource.druid.max-wait=3000
# 平峰期动态调整
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
6. 典型问题排查实录
6.1 号源超卖问题
现象:同一号源被多个患者成功预约
排查过程:
- 检查Redis锁有效期(发现设置为秒而非毫秒)
- 验证Lua脚本原子性(发现变量作用域错误)
- 最终方案:改用Redisson的RLock实现
6.2 定时任务堆积
现象:凌晨批量任务未及时完成
优化方案:
- 引入Elastic-Job分片执行
- 关键任务添加补偿机制
- 增加任务执行监控告警
7. 源码结构说明
项目采用标准Maven多模块设计:
code复制hospital-registration
├── registration-api // 接口定义
├── registration-service // 核心业务
├── registration-dao // 数据访问
├── registration-job // 定时任务
└── registration-web // 控制层
重点推荐几个关键实现:
- ScheduleController中的@RateLimiter注解实现API限流
- RegistrationQueueManager处理不同优先级挂号请求
- DistributedLockAspect切面统一管理分布式锁
8. 部署与监控方案
8.1 容器化部署
使用Docker Compose编排:
yaml复制services:
registration-service:
image: hospital/registration:1.2.0
deploy:
resources:
limits:
cpus: '2'
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 5s
retries: 3
8.2 监控指标配置
Prometheus关键指标:
yaml复制- pattern: registration.api.timer<name=registration.createOrder,quantile=0.99>
name: "registration_create_order_latency"
help: "99th percentile latency of create order API"
- pattern: cache.redis.hits<name=schedule.*>
name: "redis_schedule_cache_hits"
help: "Schedule cache hit count"
实际部署时,这套系统在4核8G的ECS上能稳定支撑8000+的QPS。有个特别要注意的点:医院业务存在明显的"月初效应",每月1号凌晨需要提前扩容50%的计算资源应对体检预约高峰。
