通用资源调度预约系统 —— 架构设计与方案分享

本文不涉及任何源代码实现,仅从架构设计和方案层面进行探讨。

一、系统定位

在很多行业中都存在这样的场景:有若干可调度的资源(设备、场地、人力),有若干需要使用资源的任务,系统需要将任务智能地分配到合适的资源和时间窗口上。

例如:

  • 医疗场景:将患者的检查申请分配到合适的设备和时段
  • 教育场景:将课程安排到教室和时间窗口
  • 物流场景:将运输任务分配到车辆和时段
  • 实验室场景:将实验任务分配到仪器和时段

本文以实际项目经验为基础,抽象出一套通用资源调度预约系统的架构设计方案。


二、核心领域模型

2.1 三大核心实体

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   资源池(Queue)  │────▶│  时段(Slot)      │◀────│ 任务(Order)     │
│                  │     │                  │     │                  │
│ - 名称           │     │ - 日期           │     │ - 任务名称       │
│ - 所属组织       │     │ - 开始/结束时间   │     │ - 任务项ID       │
│ - 排班模式       │     │ - 各来源容量上限  │     │ - 来源类型       │
│ - 优先级         │     │ - 已用数量       │     │ - 预约状态       │
│ - 强制归集标识   │     │ - 工作模式       │     │ - 合并标识       │
└─────────────────┘     └─────────────────┘     └─────────────────┘

资源池(Resource Pool):代表一组可调度的资源,例如某台设备、某个场地。核心配置包括:

  • 所属组织/部门
  • 排班模式(全天/分时段)
  • 最大预约天数
  • 强制归集标识(将关联任务强制调度到同一资源池)

时段(Time Slot):资源池在特定时间窗口内的可用容量。核心设计是按来源类型隔离容量,例如:

  • A类来源容量上限 50,已用 30
  • B类来源容量上限 20,已用 10
  • C类来源容量上限 -1(不限制)
  • 总容量上限 60

任务(Task/Order):需要被调度的最小工作单元。包含任务项关联、来源类型、预约状态、合并标识等。

2.2 任务项配置(Item Config)

任务项是系统中"可调度事项"的定义,类似于商品SKU。每个任务项配置包括:

  • 名称、编码
  • 预计耗时
  • 前置准备时间和准备类型
  • 匹配优先级
  • 允许的预约方式

2.3 资源池-任务项绑定(Pool-Item Binding)

多对多关系,描述"某个资源池可以处理哪些任务项",同时配置:

  • 该任务项在该资源池的预计用时
  • 工作日工作时间
  • 节假日工作时间
  • 优先匹配时间窗口

三、核心调度算法

3.1 整体流程

输入:一组待调度的任务
  │
  ▼
Step 1: 获取任务项配置(名称、耗时、准备类型等)
  │
  ▼
Step 2: 查询约束规则
  ├── 合并规则(哪些任务可以合并到同一时段)
  ├── 排斥规则(哪些任务不能在同一时段)
  └── 时间限制规则(哪些任务有建议的调度时间范围)
  │
  ▼
Step 3: 匹配资源池和时段
  ├── 根据任务项找到可处理的资源池
  ├── 按来源类型验证容量
  └── 按工作时间过滤有效时段
  │
  ▼
Step 4: 智能分组
  ├── 强制归集分组:相同归集标识的任务归入同一资源池
  ├── 合并分组:可合并的任务分配到同一时段
  ├── 排斥分组:互相排斥的任务分配到不同时段
  ├── 时间限制分组:按建议时间范围匹配
  └── 普通分组:无特殊约束的任务
  │
  ▼
Step 5: 执行匹配
  ├── 强制归集任务 → 直接锁定目标资源池
  ├── 剩余任务 → 按策略匹配最佳时段
  │   ├── 策略A:最快完成(优先最近的可用时段)
  │   └── 策略B:最少移动(优先同一资源池的连续时段)
  └── 输出:每个任务的推荐资源池 + 时段

3.2 合并与排斥机制

合并机制:某些任务项配置了相同的"合并类型",系统会尝试将它们安排到同一时段,减少用户的等待和移动。例如:

  • 任务A(准备类型=P)和任务B(准备类型=P)→ 合并到同一时段
  • 合并后,增强型任务优先排在前面

排斥机制:某些任务项之间存在互斥关系(如使用相同资源但不能同时进行),系统会将它们安排到不同时段。排斥还支持时间窗口约束,例如"任务A完成后48小时内不能做任务B"。

关键设计:合并和排斥是互斥的——存在排斥关系的任务项不会被合并。

3.3 强制归集机制

当某个资源池配置了"强制归集"标识后,只要待调度的任务项中存在匹配该归集标识的项,所有具有相同归集标识的任务都会被强制调度到该资源池。

归集组X = {任务A(归集标识=X), 任务B(归集标识=X), 任务C(归集标识=X)}

如果资源池R配置了归集组X → 任务A、B、C全部调度到资源池R
任务D(归集标识=Y) → 走正常匹配流程

这解决了一个常见场景:多个关联任务必须在同一资源上完成

3.4 容量管理

容量管理的核心设计是按来源类型隔离

时段T1:
  ├── 总容量上限: 60
  ├── 来源A容量: 50 (已用 30)
  ├── 来源B容量: 20 (已用 10)
  └── 来源C容量: -1 (不限)

调度任务时:
  1. 检查任务来源类型对应的容量是否已满
  2. 检查总容量是否已满
  3. 任一条件不满足 → 跳过该时段

这种设计保证了不同类型来源的资源隔离,避免某一类型占用全部容量。


四、系统架构设计

4.1 整体架构

                    ┌──────────────────────────────────────┐
                    │           多终端接入层                  │
                    │  ┌──────┐  ┌──────┐  ┌──────┐        │
                    │  │管理端 │  │操作端 │  │用户端 │        │
                    │  └──┬───┘  └──┬───┘  └──┬───┘        │
                    └─────┼────────┼────────┼──────────────┘
                          │        │        │
                    ┌─────▼────────▼────────▼──────────────┐
                    │           API 网关层                    │
                    │  认证鉴权 / 路由分发 / 限流熔断           │
                    └─────────────┬────────────────────────┘
                                  │
                    ┌─────────────▼────────────────────────┐
                    │           业务服务层                    │
                    │  ┌──────────────┐  ┌──────────────┐  │
                    │  │ 调度引擎服务  │  │ 资源管理服务  │  │
                    │  │              │  │              │  │
                    │  │ - 智能推荐   │  │ - 资源池管理  │  │
                    │  │ - 合并/排斥  │  │ - 时段管理   │  │
                    │  │ - 容量校验   │  │ - 任务项管理  │  │
                    │  │ - 状态流转   │  │ - 排班模板   │  │
                    │  └──────────────┘  └──────────────┘  │
                    │  ┌──────────────┐  ┌──────────────┐  │
                    │  │ 任务管理服务  │  │ 通知服务     │  │
                    │  │              │  │              │  │
                    │  │ - 任务CRUD   │  │ - 消息推送   │  │
                    │  │ - 状态跟踪   │  │ - 短信/微信  │  │
                    │  │ - 历史记录   │  │ - 第三方集成 │  │
                    │  └──────────────┘  └──────────────┘  │
                    └─────────────┬────────────────────────┘
                                  │
                    ┌─────────────▼────────────────────────┐
                    │           基础设施层                    │
                    │  ┌────────┐ ┌───────┐ ┌───────────┐  │
                    │  │ MySQL  │ │ Redis │ │ MQ队列     │  │
                    │  └────────┘ └───────┘ └───────────┘  │
                    │  ┌────────┐ ┌───────┐ ┌───────────┐  │
                    │  │ XXL-Job│ │ OSS   │ │ 监控中心   │  │
                    │  └────────┘ └───────┘ └───────────┘  │
                    └──────────────────────────────────────┘

4.2 技术选型

层次 技术 选型理由
Web容器 Undertow 比Tomcat更高的吞吐量,更低的内存占用
ORM MyBatis-Plus 灵活的SQL控制 + 便捷的CRUD操作
认证 Sa-Token + JWT 轻量级、高性能的认证方案
缓存 Redis + Redisson 分布式锁、缓存、分布式会话
消息队列 RabbitMQ 异步通知、解耦、削峰
定时任务 XXL-Job 分布式任务调度、可视化管理
多数据源 Dynamic Datasource 支持多库场景,动态切换
连接池 HikariCP Spring Boot默认,高性能连接池

4.3 多终端架构

系统采用多模块单体架构,通过不同的入口模块服务不同终端:

┌─────────────────────────────────────────┐
│            公共模块 (common)              │
│  枚举定义 / 工具类 / 通用组件             │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│            系统模块 (system)              │
│  领域模型 / Service / Mapper / XML       │
└────────────────┬────────────────────────┘
                 │
┌────────┬───────┴────────┬───────────────┐
│ 管理端  │   操作端       │   用户端      │
│ (admin) │  (nurse)      │   (app)       │
│ 系统配置 │  现场操作     │   自助预约    │
│ 排班管理 │  号源调整     │   查询取消    │
│ 数据统计 │  患者叫号     │   通知接收    │
└────────┴───────────────┴───────────────┘

三个终端模块共享同一套业务逻辑(system模块),但各自独立部署、独立配置,可根据负载情况独立扩展。


五、关键设计决策

5.1 分布式锁策略

调度场景下的并发控制至关重要。系统采用Redis分布式锁来保证:

  • 同一时段的容量扣减是原子操作
  • 防止超卖(容量溢出)
  • 锁的粒度控制在"资源池+时段"级别
锁的Key设计:lock:{poolId}:{slotId}
超时时间:30秒
获取超时:3秒

5.2 异步通知机制

调度结果需要通知下游系统(如执行系统、PACS系统等),采用MQ异步通知

  • 调度成功后立即返回,通知异步发送
  • 通知失败时记录到重试队列
  • 支持多种通知渠道(MQ、HTTP回调、WebSocket)

5.3 排班模板与自动排班

支持模板化排班,管理员可以:

  1. 配置排班模板(工作日模式、节假日模式、时段分组)
  2. 一键生成指定日期范围的排班
  3. 节假日自动同步调整
  4. 批量开关排班、批量设置工作模式

5.4 第三方系统集成

通过数据同步层与上游系统(如HIS、LIS等)对接:

  • RabbitMQ监听数据变更事件
  • 支持多种数据库类型(MySQL、Oracle、SQL Server、PostgreSQL)
  • 动态数据源 + 动态驱动加载
  • 字段映射可配置化

六、扩展性设计

6.1 资源池无限扩展

新增资源(如新设备、新场地)只需:

  1. 创建新的资源池记录
  2. 绑定任务项
  3. 配置排班
  4. 系统自动纳入调度

6.2 任务项类型扩展

通过任务项的树形结构类型字段,支持无限扩展任务类型,无需修改代码。

6.3 调度策略扩展

调度算法通过策略模式设计,新增调度策略只需实现接口:

  • 最快完成策略
  • 最少移动策略
  • 负载均衡策略
  • 优先级策略
  • ...(可自定义扩展)

6.4 多租户支持

通过数据源隔离 + 组织机构树,天然支持多租户场景。


七、性能优化要点

  1. 批量操作优化:MySQL rewriteBatchedStatements=true,大幅提升批量写入性能
  2. 连接池调优:HikariCP 参数精细化配置,根据实际负载调整
  3. 缓存策略:热点数据(如任务项配置、资源池配置)使用Redis缓存
  4. 线程池管理:异步通知使用独立线程池,避免影响主流程
  5. SQL优化:MyBatis-Plus条件构造器避免N+1查询,合理使用索引
  6. Undertow容器:相比Tomcat有更高的并发处理能力

八、总结

这套通用资源调度预约系统的核心设计理念是:

  1. 领域驱动:资源池、时段、任务三大核心实体清晰分离
  2. 规则引擎化:合并、排斥、时间限制等规则可配置化,不硬编码
  3. 容量隔离:按来源类型隔离容量,保证公平性
  4. 强制归集:支持关联任务的强制聚合调度
  5. 多终端统一:一套业务逻辑服务多个终端,独立部署独立扩展
  6. 高可扩展:资源、任务类型、调度策略均可配置化扩展

这套架构不仅适用于医疗场景,任何涉及"资源-时段-任务"三方调度的场景都可以复用这套设计模式。

posted @ 2026-07-09 11:40  Rolay  阅读(6)  评论(0)    收藏  举报