CI/CD Pipeline / test-admin (push) Waiting to run
CI/CD Pipeline / test-bigscreen (push) Waiting to run
CI/CD Pipeline / build-push (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / update-deploy (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-pr (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / security-scan (push) Has been cancelled
CI/CD Pipeline / test-build-boot (push) Has been cancelled
新增核心功能: - 健康画像生成系统(用户/部门/组织基线) - 风险评估框架(心血管/运动/呼吸/睡眠) - 行为画像分析(饮食/运动/睡眠/健康关注度) - 数据质量评分和告警 数据库迁移: - V1.3.0~V1.7.0 健康监测表结构 前端增强: - ljwx-admin: BigScreen集成、健康搜索优化 - ljwx-bigscreen: SSO认证、登录界面 文档体系: - 强制文档管理规范(kebab-case、分类、Git hooks) - 架构文档、开发指南、运维手册 - 工程蓝图 v2.1 CI/CD: - 文档验证工作流 - 生产就绪性检查脚本 - 完整测试覆盖 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
18 KiB
18 KiB
Phase 1 画像调度架构设计
任务 ID: T1.2.1 设计人: Backend Dev 1 设计日期: 2026-01-20 评审状态: 待评审
1. 架构概览
1.1 设计目标
核心问题: 当前系统中,画像生成与评分计算耦合在一起,导致:
- 评分计算依赖实时画像生成,性能差
- 画像数据无法复用,重复计算
- 调度策略不灵活
解决方案: 实现画像层独立调度,解耦画像生成与评分计算。
1.2 架构原则
- 单一职责: 画像生成服务只负责生成画像,不参与评分计算
- 数据持久化: 画像数据持久化到数据库,供评分层使用
- 独立调度: 画像生成和评分计算独立调度,互不影响
- 增量更新: 支持增量更新画像数据,减少计算量
2. 系统架构
2.1 层次架构
┌─────────────────────────────────────────────────────────────┐
│ 评分层 (Scoring Layer) │
│ HealthScoreService - 依赖画像数据计算健康评分 │
└─────────────────────────────────────────────────────────────┘
▲
│ 读取画像数据
│
┌─────────────────────────────────────────────────────────────┐
│ 画像层 (Profile Layer) ⭐ 新增 │
│ HealthProfileService - 从状态数据生成健康画像 │
│ HealthProfileScheduledTask - 定时调度画像生成 │
└─────────────────────────────────────────────────────────────┘
▲
│ 读取状态数据
│
┌─────────────────────────────────────────────────────────────┐
│ 状态层 (State Layer) │
│ 原始健康数据: heart_rate, blood_oxygen, temperature... │
└─────────────────────────────────────────────────────────────┘
2.2 核心组件
2.2.1 HealthProfileService
职责: 从状态数据生成用户健康画像
核心方法:
// 为单个用户生成画像
HealthProfile generateUserProfile(Long userId, LocalDate date);
// 批量生成画像(性能优化)
List<HealthProfile> batchGenerateProfiles(List<Long> userIds, LocalDate date);
// 增量更新画像(仅更新变化的指标)
HealthProfile updateProfileIncremental(Long userId, LocalDate date);
2.2.2 HealthProfileScheduledTask
职责: 定时调度画像生成任务
调度策略:
- 触发时间: 每日 01:30(避开业务高峰)
- 执行范围: 所有活跃用户(过去 7 天有数据的用户)
- 批处理: 每批 200 用户(避免 OOM)
- 错误处理: 失败任务记录日志,不影响其他用户
伪代码:
@Scheduled(cron = "0 30 1 * * ?")
public void generateDailyProfiles() {
LocalDate yesterday = LocalDate.now().minusDays(1);
// 1. 获取活跃用户列表
List<Long> activeUserIds = getActiveUsers(yesterday);
// 2. 分批处理
Lists.partition(activeUserIds, 200).forEach(batch -> {
try {
healthProfileService.batchGenerateProfiles(batch, yesterday);
} catch (Exception e) {
log.error("Failed to generate profiles for batch", e);
}
});
// 3. 更新调度任务状态
updateTaskStatus("profile_generation", yesterday, "COMPLETED");
}
2.2.3 HealthProfileRepository
职责: 画像数据持久化
核心方法:
// 保存画像
void save(HealthProfile profile);
// 批量保存
void batchSave(List<HealthProfile> profiles);
// 查询画像
HealthProfile findByUserIdAndDate(Long userId, LocalDate date);
// 查询最新画像
HealthProfile findLatestByUserId(Long userId);
3. 数据模型
3.1 画像数据表结构
表名: t_user_health_profile
| 字段名 | 类型 | 说明 | 索引 |
|---|---|---|---|
| id | BIGINT | 主键(自增) | PK |
| user_id | BIGINT | 用户 ID | IDX |
| customer_id | BIGINT | 租户 ID | IDX |
| profile_date | DATE | 画像日期 | IDX |
| heart_rate_avg | DECIMAL(5,2) | 平均心率 | - |
| heart_rate_max | DECIMAL(5,2) | 最大心率 | - |
| heart_rate_min | DECIMAL(5,2) | 最小心率 | - |
| heart_rate_variability | DECIMAL(5,2) | 心率变异性 (HRV) | - |
| blood_oxygen_avg | DECIMAL(5,2) | 平均血氧 | - |
| blood_oxygen_min | DECIMAL(5,2) | 最低血氧 | - |
| temperature_avg | DECIMAL(5,2) | 平均体温 | - |
| pressure_high_avg | DECIMAL(5,2) | 平均收缩压 | - |
| pressure_low_avg | DECIMAL(5,2) | 平均舒张压 | - |
| stress_level_avg | DECIMAL(5,2) | 平均压力水平 | - |
| sleep_duration | INT | 睡眠时长(分钟) | - |
| sleep_deep_duration | INT | 深睡时长(分钟) | - |
| sleep_quality_score | DECIMAL(5,2) | 睡眠质量评分 | - |
| step_count | INT | 步数 | - |
| calorie_burned | INT | 消耗卡路里 | - |
| distance_meters | INT | 运动距离(米) | - |
| data_completeness | DECIMAL(5,2) | 数据完整度(0-100) | - |
| created_at | TIMESTAMP | 创建时间 | - |
| updated_at | TIMESTAMP | 更新时间 | - |
索引设计:
-- 唯一索引: 用户 + 日期(防止重复)
CREATE UNIQUE INDEX idx_user_date
ON t_user_health_profile(user_id, profile_date);
-- 组合索引: 租户 + 日期(多租户查询优化)
CREATE INDEX idx_customer_date
ON t_user_health_profile(customer_id, profile_date);
-- 索引: 用户 ID(查询最新画像)
CREATE INDEX idx_user_id
ON t_user_health_profile(user_id);
3.2 画像生成任务状态表
表名: t_profile_task_status
| 字段名 | 类型 | 说明 | 索引 |
|---|---|---|---|
| id | BIGINT | 主键(自增) | PK |
| task_name | VARCHAR(100) | 任务名称 | IDX |
| task_date | DATE | 任务日期 | IDX |
| status | VARCHAR(20) | 任务状态 (PENDING/RUNNING/COMPLETED/FAILED) | - |
| total_users | INT | 总用户数 | - |
| processed_users | INT | 已处理用户数 | - |
| failed_users | INT | 失败用户数 | - |
| start_time | TIMESTAMP | 开始时间 | - |
| end_time | TIMESTAMP | 结束时间 | - |
| error_message | TEXT | 错误信息 | - |
| created_at | TIMESTAMP | 创建时间 | - |
| updated_at | TIMESTAMP | 更新时间 | - |
4. 时序图
4.1 画像生成流程
┌─────────┐ ┌────────────────┐ ┌─────────────────┐ ┌──────────┐
│ Quartz │ │ScheduledTask │ │ProfileService │ │Repository│
└────┬────┘ └───────┬────────┘ └────────┬────────┘ └────┬─────┘
│ │ │ │
│ 01:30 触发 │ │ │
├─────────────────────>│ │ │
│ │ │ │
│ │ 1. 获取活跃用户列表 │ │
│ ├──────────────────────────>│ │
│ │ │ SELECT user_id │
│ │ ├──────────────────────>│
│ │ │<──────────────────────┤
│ │<──────────────────────────┤ List<userId> │
│ │ │ │
│ │ 2. 分批处理(200/批) │ │
│ │ for each batch: │ │
│ │ │ │
│ │ 3. 批量生成画像 │ │
│ ├──────────────────────────>│ │
│ │ │ │
│ │ │ 4. 查询状态数据 │
│ │ │ (heart_rate, │
│ │ │ blood_oxygen...) │
│ │ ├──────────────────────>│
│ │ │<──────────────────────┤
│ │ │ │
│ │ │ 5. 计算画像指标 │
│ │ │ (avg, max, min...) │
│ │ │ │
│ │ │ 6. 批量保存画像 │
│ │ ├──────────────────────>│
│ │ │<──────────────────────┤
│ │<──────────────────────────┤ │
│ │ │ │
│ │ 7. 更新任务状态 │ │
│ ├──────────────────────────────────────────────────>│
│ │<──────────────────────────────────────────────────┤
│ │ │ │
4.2 评分层调用画像数据
┌────────────┐ ┌──────────────┐ ┌─────────────┐
│ScoreService│ │ProfileService│ │Repository │
└─────┬──────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
│ 1. 计算用户健康评分 │ │
│ │ │
│ 2. 获取用户画像 │ │
├──────────────────────>│ │
│ │ SELECT * FROM profile │
│ ├───────────────────────>│
│ │<───────────────────────┤
│<──────────────────────┤ HealthProfile │
│ │ │
│ 3. 基于画像计算评分 │ │
│ (heart_rate_score, │ │
│ blood_oxygen_score...) │ │
│ │ │
│ 4. 返回评分结果 │ │
5. API 接口设计
5.1 画像生成接口
POST /api/health/profile/generate
描述: 手动触发画像生成(用于测试或补数)
请求参数:
{
"userIds": [1001, 1002, 1003],
"startDate": "2026-01-01",
"endDate": "2026-01-07"
}
响应:
{
"code": 200,
"message": "成功",
"data": {
"totalUsers": 3,
"processedUsers": 3,
"failedUsers": 0,
"duration": 1234
}
}
5.2 查询画像接口
GET /api/health/profile/{userId}
描述: 查询用户健康画像
请求参数:
userId(路径参数): 用户 IDdate(查询参数, 可选): 指定日期,默认最新
响应:
{
"code": 200,
"message": "成功",
"data": {
"userId": 1001,
"profileDate": "2026-01-19",
"heartRate": {
"avg": 72.5,
"max": 120,
"min": 55,
"variability": 45.2
},
"bloodOxygen": {
"avg": 97.8,
"min": 95
},
"temperature": {
"avg": 36.5
},
"sleep": {
"duration": 420,
"deepDuration": 120,
"qualityScore": 85.5
},
"activity": {
"stepCount": 8500,
"calorieBurned": 2100,
"distanceMeters": 6200
},
"dataCompleteness": 92.5
}
}
5.3 任务状态查询接口
GET /api/health/profile/task/status
描述: 查询画像生成任务状态
请求参数:
taskName(查询参数): 任务名称,默认 "profile_generation"date(查询参数, 可选): 任务日期,默认今天
响应:
{
"code": 200,
"message": "成功",
"data": {
"taskName": "profile_generation",
"taskDate": "2026-01-20",
"status": "COMPLETED",
"totalUsers": 1000,
"processedUsers": 1000,
"failedUsers": 0,
"startTime": "2026-01-20T01:30:00",
"endTime": "2026-01-20T01:35:23",
"duration": 323
}
}
6. 性能优化
6.1 批处理策略
- 批量大小: 200 用户/批
- 并发控制: 使用
@Async+ 线程池(核心线程 4,最大线程 8) - 数据库批量插入: 使用 MyBatis-Plus
saveBatch()
6.2 查询优化
- 索引优化: 为
user_id + profile_date创建唯一索引 - 连接池: Druid 连接池(基础 30,最大 80)
- 缓存: 最新画像数据缓存 5 分钟(Redis)
6.3 计算优化
- 增量计算: 如果当天已有画像,仅更新变化的指标
- 数据预聚合: 状态数据按天预聚合,减少计算量
7. 监控与告警
7.1 性能指标
| 指标 | 目标 | 监控方式 |
|---|---|---|
| 画像生成时长 | 1000 用户 <5 分钟 | Prometheus + Grafana |
| 任务成功率 | >99% | 任务状态表统计 |
| 数据完整度 | 平均 >90% | 画像数据 data_completeness 字段 |
| 数据库查询 P99 | <100ms | Druid 监控 |
7.2 告警规则
- 任务失败: 任务状态 = FAILED,立即告警
- 任务超时: 任务执行时间 >10 分钟,告警
- 数据完整度低: 平均完整度 <80%,告警
8. 风险评估
| 风险 | 概率 | 影响 | 应对措施 |
|---|---|---|---|
| 大批量用户导致 OOM | 中 | 高 | 分批处理 + JVM 内存监控 |
| 数据库锁表 | 低 | 高 | 使用批量插入 + 避免高峰期执行 |
| 调度任务延期 | 中 | 中 | 监控任务执行时长,调整调度时间 |
| 画像数据质量差 | 中 | 中 | 数据完整度评分 + 异常值过滤 |
9. 测试计划
9.1 单元测试
-
HealthProfileService:
- 测试画像生成逻辑(正常数据)
- 测试画像生成逻辑(缺失数据)
- 测试批量生成性能
-
HealthProfileScheduledTask:
- 测试调度任务触发
- 测试错误处理
9.2 集成测试
- 端到端测试: 状态数据 → 画像生成 → 评分计算
- 性能测试: 1000 用户画像生成 <5 分钟
9.3 验收标准
- ✅ 单元测试覆盖率 >80%
- ✅ 画像生成成功率 >99%
- ✅ 性能达标: 1000 用户 <5 分钟
- ✅ 数据完整度 >90%
- ✅ Code Review 通过
10. 实施计划
| 任务 | 负责人 | 工期 | 依赖 |
|---|---|---|---|
| T1.2.1: 架构设计 | Backend Dev 1 | 2天 | - |
| T1.2.2: 实现画像生成服务 | Backend Dev 1 | 3天 | T1.2.1 |
| T1.2.3: 实现调度任务 | Backend Dev 1 | 2天 | T1.2.2 |
| T1.2.4: 修改评分任务依赖 | Backend Dev 1 | 2天 | T1.2.3 |
| T1.2.5: 集成测试 | QA | 2天 | T1.2.4 |
| T1.2.6: Code Review | Team | 1天 | T1.2.5 |
11. 附录
11.1 参考文档
11.2 变更记录
| 日期 | 版本 | 变更内容 | 变更人 |
|---|---|---|---|
| 2026-01-20 | v1.0 | 初始版本 | Backend Dev 1 |
评审签字:
- Tech Lead: _____________ 日期: _______
- Backend Dev 2: _____________ 日期: _______
- DevOps: _____________ 日期: _______