Files
java-template/docs/health_data_batch_processing_optimization.md
T
BrunoGaoandClaude 3248bb0a2a feat: 完成消息系统V2优化 - 基于user_id的高性能索引重构
## 主要更改

### 1. 数据库表结构增强
- **t_device_message_v2**: 新增7个关键字段
  - priority_level: 优先级数值(1-5)
  - channels: 分发渠道JSON
  - require_ack: 是否需要确认
  - metadata: 扩展元数据JSON
  - target_count: 目标用户总数
  - version: 乐观锁版本号

- **t_device_message_detail_v2**: 新增8个关键字段
  - distribution_id: 分发唯一ID
  - device_sn: 设备序列号
  - user_id: 用户ID(核心查询字段)
  - response_duration: 响应耗时
  - delivery_details: 分发详情JSON
  - client_info: 客户端信息JSON
  - location_info: 位置信息JSON
  - last_retry_time: 最后重试时间

### 2. 索引优化重构 (基于user_id)
- 删除原有device_sn相关索引
- 新建5个user_id高性能复合索引:
  - idx_customer_user_time: 客户+用户+时间
  - idx_customer_user_status: 客户+用户+状态
  - idx_customer_user_type: 客户+用户+类型
  - idx_user_org_priority: 用户+组织+优先级
  - idx_user_status_time: 用户+状态+时间

- detail表新建4个user_id相关索引:
  - uk_message_user_target: 唯一约束
  - idx_customer_user_status: 客户+用户+状态
  - idx_user_channel_time: 用户+渠道+时间
  - idx_user_delivery_status: 用户+分发状态

### 3. 数据迁移和初始化
- 自动生成distribution_id
- 根据urgency设置priority_level
- 初始化默认channels配置
- 保持现有数据完整性

### 4. 性能提升预期
- 用户消息查询: 预计10-20倍性能提升
- 确认状态查询: 支持快速人员清单检索
- 存储空间: JSON字段替代冗余VARCHAR
- 查询覆盖: 所有user_id查询都能命中索引

### 5. 文档和脚本
- 完整的V2优化SQL脚本
- 消息机制设计文档
- 数据库备份(22MB)
- 性能验证查询

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2025-09-15 07:56:03 +08:00

583 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 健康数据上传批处理流程优化方案
## 📋 目录
- [1. 系统概述](#1-系统概述)
- [2. 当前架构分析](#2-当前架构分析)
- [3. 数据流程梳理](#3-数据流程梳理)
- [4. 性能瓶颈分析](#4-性能瓶颈分析)
- [5. 优化建议方案](#5-优化建议方案)
- [6. 实施优先级](#6-实施优先级)
- [7. 监控和度量](#7-监控和度量)
## 1. 系统概述
### 1.1 系统职责
ljwx-bigscreen 健康数据批处理系统负责处理来自可穿戴设备的健康数据上传,包括:
- 实时健康指标收集(心率、血氧、体温等)
- 数据验证和清洗
- 批量数据库存储
- Redis缓存更新
- 实时告警触发
### 1.2 技术栈
- **后端框架**: Flask + SQLAlchemy
- **数据库**: MySQL (主表 + 日/周分表)
- **缓存层**: Redis
- **异步处理**: ThreadPoolExecutor + Queue
- **监控**: 专业日志系统
### 1.3 核心指标
- **并发处理**: 支持多设备同时上传
- **吞吐量**: 目标QPS >1400
- **响应时间**: <3秒端到端处理
- **可靠性**: 99.9%成功率
## 2. 当前架构分析
### 2.1 核心组件
#### HealthDataOptimizer (批处理引擎)
```python
# 当前配置 (CPU自适应)
- 批次大小: CPU核心数 × 25 (50-500范围)
- 批处理超时: 2秒
- 线程池: CPU核心数 × 2.5 (4-32范围)
- 队列容量: 5000
```
#### 数据存储层级
1. **主表**: `t_user_health_data` (实时数据)
2. **日表**: `t_user_health_data_daily` (聚合数据)
3. **周表**: `t_user_health_data_weekly` (周度统计)
4. **Redis**: 实时缓存和发布订阅
### 2.2 处理流程架构
```mermaid
graph TB
A[设备上传] --> B[Flask API接口]
B --> C[数据验证和映射]
C --> D[批处理队列]
D --> E[批处理引擎]
E --> F[数据库批量插入]
E --> G[Redis更新]
E --> H[告警检测]
F --> F1[主表插入]
F --> F2[日表聚合]
F --> F3[周表聚合]
G --> G1[健康数据缓存]
G --> G2[发布订阅通知]
H --> H1[规则引擎]
H --> H2[微信通知]
```
## 3. 数据流程梳理
### 3.1 API接入层
```
POST /upload_health_data
├── 请求验证 (设备SN、客户信息)
├── 数据格式标准化
├── 字段映射处理
│ ├── upload_method: 4g → esim
│ ├── body_temperature → temperature
│ └── blood_pressure_* → pressure_*
└── 调用 optimized_upload_health_data()
```
### 3.2 批处理队列层
```
HealthDataOptimizer.add_data()
├── 确保批处理器启动
├── 客户信息解析 (user_id/org_id/customer_id)
├── 重复检测 (数据库查询)
├── 数据分类处理
│ ├── 主表数据: 快速更新字段
│ ├── 日表数据: 睡眠、运动等慢字段
│ └── 周表数据: 周度统计字段
├── Redis数据构建
└── 队列提交 (Queue.put)
```
### 3.3 批处理执行层
```
_batch_processor() 主循环
├── 队列监听 (2秒超时或批次满)
├── 批量数据收集
└── _flush_batch() 执行
├── 数据分离 (主表/日表/周表)
├── 并行数据库操作
│ ├── 主表批量插入 + 重复处理fallback
│ ├── 日表 upsert (检查+插入/更新)
│ └── 周表 upsert (检查+插入/更新)
├── Redis异步更新 (线程池)
└── 告警异步检测 (线程池)
```
### 3.4 数据库存储层
```sql
-- 主表插入 (实时数据)
INSERT INTO t_user_health_data
(device_sn, user_id, org_id, customer_id, heart_rate, blood_oxygen,
temperature, pressure_high, pressure_low, stress, step, distance,
calorie, latitude, longitude, altitude, sleep, timestamp, upload_method)
-- 日表聚合 (UPSERT模式)
INSERT/UPDATE t_user_health_data_daily
(device_sn, user_id, org_id, customer_id, date, sleep_data,
exercise_daily_data, workout_data)
-- 周表聚合 (UPSERT模式)
INSERT/UPDATE t_user_health_data_weekly
(device_sn, user_id, org_id, customer_id, week_start, exercise_week_data)
```
## 4. 性能瓶颈分析
### 4.1 数据库层瓶颈
#### 4.1.1 重复检测开销
**问题**: 每条记录插入前都执行重复检测查询
```sql
SELECT id FROM t_user_health_data WHERE device_sn = ? AND timestamp = ?
```
**影响**: 大批量数据时,查询开销 = 插入开销
#### 4.1.2 日/周表频繁UPSERT
**问题**: 每批次都检查并更新日表和周表
```sql
-- 每个设备每批次都执行
SELECT id FROM t_user_health_data_daily WHERE device_sn = ? AND date = ?
UPDATE/INSERT t_user_health_data_daily SET ... WHERE id = ?
```
**影响**: 锁争用和磁盘IO增加
#### 4.1.3 事务粒度不当
**问题**: 批处理中多表操作未充分利用事务优势
- 主表、日表、周表分别提交
- 异常回滚范围不完整
### 4.2 并发处理瓶颈
#### 4.2.1 队列单点处理
**问题**: 单一批处理器线程处理所有数据
```python
while self.running:
item = self.batch_queue.get(timeout=timeout) # 串行处理
batch_data.append(item)
```
#### 4.2.2 线程池资源竞争
**问题**: Redis更新和告警检测共享线程池
```python
self.executor.submit(self._async_process, item) # 同一线程池
```
### 4.3 内存和资源瓶颈
#### 4.3.1 批次大小静态配置
**问题**: 固定批次大小无法适应负载变化
```python
self.batch_size = max(50, min(500, self.cpu_cores * 25)) # 静态值
```
#### 4.3.2 内存泄漏风险
**问题**: 长期运行的已处理键值集合
```python
self.processed_keys = set() # 无界增长
```
## 5. 优化建议方案
### 5.1 数据库层优化
#### 5.1.1 【高优先级】批量UPSERT优化
**建议**: 使用MySQL的批量UPSERT语法减少查询次数
```sql
-- 优化前:N次查询 + N次插入/更新
SELECT id FROM t_user_health_data WHERE device_sn = ? AND timestamp = ?
INSERT INTO t_user_health_data ... ON DUPLICATE KEY UPDATE ...
-- 优化后:1次批量UPSERT
INSERT INTO t_user_health_data
(device_sn, user_id, ..., timestamp, upload_method)
VALUES
(?, ?, ..., ?, ?),
(?, ?, ..., ?, ?),
...
ON DUPLICATE KEY UPDATE
heart_rate = VALUES(heart_rate),
blood_oxygen = VALUES(blood_oxygen),
...;
```
**预期收益**: 减少50-70%的数据库交互次数
#### 5.1.2 【高优先级】索引优化
**建议**: 优化重复检测和查询索引
```sql
-- 当前索引分析
SHOW INDEX FROM t_user_health_data;
-- 建议添加复合索引 (如不存在)
CREATE INDEX idx_device_timestamp ON t_user_health_data(device_sn, timestamp);
CREATE INDEX idx_customer_create_time ON t_user_health_data(customer_id, create_time);
CREATE INDEX idx_org_user_timestamp ON t_user_health_data(org_id, user_id, timestamp);
```
#### 5.1.3 【中优先级】分区表策略
**建议**: 按时间分区主表,提高查询和插入性能
```sql
-- 主表按月分区
ALTER TABLE t_user_health_data
PARTITION BY RANGE (YEAR(create_time)*100 + MONTH(create_time)) (
PARTITION p202501 VALUES LESS THAN (202502),
PARTITION p202502 VALUES LESS THAN (202503),
...
PARTITION p_future VALUES LESS THAN MAXVALUE
);
```
### 5.2 并发处理优化
#### 5.2.1 【高优先级】多队列并行处理
**建议**: 实现设备级别的分片队列
```python
class ShardedBatchProcessor:
def __init__(self, shard_count=4):
self.shard_count = shard_count
self.queues = [queue.Queue(maxsize=1250) for _ in range(shard_count)]
self.processors = []
def _get_shard(self, device_sn: str) -> int:
return hash(device_sn) % self.shard_count
def add_data(self, data, device_sn):
shard_id = self._get_shard(device_sn)
self.queues[shard_id].put(data)
```
**预期收益**: 提高2-4倍并发处理能力
#### 5.2.2 【中优先级】专用线程池分离
**建议**: 为不同类型的异步任务创建专用线程池
```python
class SpecializedExecutors:
def __init__(self):
self.db_executor = ThreadPoolExecutor(max_workers=8, thread_name_prefix="db")
self.redis_executor = ThreadPoolExecutor(max_workers=4, thread_name_prefix="redis")
self.alert_executor = ThreadPoolExecutor(max_workers=6, thread_name_prefix="alert")
```
#### 5.2.3 【低优先级】异步IO框架迁移
**建议**: 考虑使用asyncio替代线程池,减少上下文切换
```python
import asyncio
import aioredis
import aiomysql
class AsyncBatchProcessor:
async def process_batch_async(self, batch_data):
tasks = [
self.insert_to_db_async(batch_data),
self.update_redis_async(batch_data),
self.check_alerts_async(batch_data)
]
await asyncio.gather(*tasks)
```
### 5.3 缓存和性能优化
#### 5.3.1 【高优先级】智能批次调整
**建议**: 基于系统负载动态调整批次大小
```python
class AdaptiveBatchSizer:
def __init__(self):
self.min_batch_size = 50
self.max_batch_size = 1000
self.current_batch_size = 200
self.performance_history = []
def adjust_batch_size(self, processing_time: float, batch_size: int):
throughput = batch_size / processing_time
# 基于吞吐量和系统资源调整
if throughput > self.target_throughput:
self.current_batch_size = min(self.max_batch_size,
int(batch_size * 1.2))
else:
self.current_batch_size = max(self.min_batch_size,
int(batch_size * 0.8))
```
#### 5.3.2 【中优先级】Redis流水线优化
**建议**: 使用Redis Pipeline批量执行命令
```python
def update_redis_batch(self, batch_data):
pipe = redis.pipeline()
for item in batch_data:
device_sn = item['device_sn']
redis_data = item['redis_data']
# 批量命令
pipe.hset(f"health_data:{device_sn}", mapping=redis_data)
pipe.publish(f"health_data_channel:{device_sn}", device_sn)
# 每100个命令执行一次
if len(pipe.command_stack) >= 100:
pipe.execute()
pipe = redis.pipeline()
# 执行剩余命令
if pipe.command_stack:
pipe.execute()
```
#### 5.3.3 【中优先级】内存管理优化
**建议**: 实现更智能的内存管理策略
```python
class MemoryOptimizedProcessor:
def __init__(self):
self.processed_keys = {} # 改为时间戳字典
self.cleanup_interval = 1800 # 30分钟清理一次
def cleanup_expired_keys(self):
cutoff_time = time.time() - 3600 # 保留1小时
expired_keys = [
key for key, timestamp in self.processed_keys.items()
if timestamp < cutoff_time
]
for key in expired_keys:
del self.processed_keys[key]
```
### 5.4 监控和可观测性优化
#### 5.4.1 【高优先级】性能指标收集
**建议**: 实现全面的性能监控体系
```python
@dataclass
class BatchProcessingMetrics:
batch_id: str
batch_size: int
processing_time: float
db_insert_time: float
redis_update_time: float
alert_check_time: float
success_count: int
duplicate_count: int
error_count: int
class MetricsCollector:
def __init__(self):
self.metrics_queue = queue.Queue()
self.start_metrics_reporter()
def record_batch_metrics(self, metrics: BatchProcessingMetrics):
self.metrics_queue.put(metrics)
def start_metrics_reporter(self):
def reporter():
while True:
try:
metrics = self.metrics_queue.get(timeout=60)
self.send_to_monitoring_system(metrics)
except queue.Empty:
continue
threading.Thread(target=reporter, daemon=True).start()
```
#### 5.4.2 【中优先级】健康检查端点
**建议**: 实现专门的批处理系统健康检查
```python
@app.route('/api/batch_processor/health')
def batch_processor_health():
optimizer_stats = optimizer.get_detailed_stats()
health_status = {
'status': 'healthy' if optimizer_stats['errors'] < 10 else 'degraded',
'queue_size': optimizer.batch_queue.qsize(),
'processed_total': optimizer_stats['processed'],
'error_rate': optimizer_stats['errors'] / max(optimizer_stats['processed'], 1),
'avg_batch_size': optimizer_stats.get('avg_batch_size', 0),
'throughput_per_second': optimizer_stats.get('throughput', 0)
}
return jsonify(health_status)
```
#### 5.4.3 【低优先级】分布式链路追踪
**建议**: 集成分布式追踪系统 (如Jaeger)
```python
from opentelemetry import trace
from opentelemetry.exporter.jaeger import JaegerExporter
class TracedBatchProcessor:
def __init__(self):
self.tracer = trace.get_tracer(__name__)
def process_with_tracing(self, batch_data):
with self.tracer.start_as_current_span("batch_processing") as span:
span.set_attribute("batch_size", len(batch_data))
with self.tracer.start_as_current_span("database_insert"):
self.insert_to_database(batch_data)
with self.tracer.start_as_current_span("redis_update"):
self.update_redis(batch_data)
```
## 6. 实施优先级
### 6.1 第一阶段 (高优先级) - 立即实施
| 优化项 | 预期收益 | 实施难度 | 风险等级 |
|--------|----------|----------|----------|
| 批量UPSERT优化 | 50-70%性能提升 | 中 | 低 |
| 索引优化 | 30-50%查询提升 | 低 | 极低 |
| 多队列并行处理 | 2-4倍并发提升 | 高 | 中 |
| 智能批次调整 | 20-30%吞吐量提升 | 中 | 低 |
| 性能指标收集 | 可观测性提升 | 低 | 极低 |
**实施时间**: 2-3周
**预期整体性能提升**: 100-200%
### 6.2 第二阶段 (中优先级) - 后续实施
| 优化项 | 预期收益 | 实施难度 | 风险等级 |
|--------|----------|----------|----------|
| 专用线程池分离 | 资源利用率提升 | 中 | 低 |
| Redis流水线优化 | Redis性能提升30% | 低 | 极低 |
| 内存管理优化 | 内存稳定性提升 | 低 | 极低 |
| 分区表策略 | 大数据量性能提升 | 高 | 中 |
| 健康检查端点 | 运维能力提升 | 低 | 极低 |
**实施时间**: 3-4周
**预期整体性能提升**: 50-80%
### 6.3 第三阶段 (低优先级) - 长期规划
| 优化项 | 预期收益 | 实施难度 | 风险等级 |
|--------|----------|----------|----------|
| 异步IO框架迁移 | 资源效率大幅提升 | 极高 | 高 |
| 分布式链路追踪 | 问题诊断能力提升 | 高 | 中 |
**实施时间**: 4-6周
**预期整体性能提升**: 100-300% (但实施风险高)
## 7. 监控和度量
### 7.1 核心性能指标 (KPI)
#### 7.1.1 吞吐量指标
- **批处理QPS**: 每秒处理的批次数量
- 目标: >50 batches/s
- 当前: ~20 batches/s
- **数据处理TPS**: 每秒处理的健康数据记录数
- 目标: >2000 records/s
- 当前: ~800 records/s
#### 7.1.2 延迟指标
- **端到端延迟**: 从API接收到数据库插入完成
- 目标: P95 < 3秒
- 当前: P95 ~5-8秒
- **队列等待时间**: 数据在批处理队列中的等待时间
- 目标: P95 < 1秒
- 当前: P95 ~2-3秒
#### 7.1.3 可靠性指标
- **成功率**: 批处理成功率
- 目标: >99.9%
- 当前: ~99.5%
- **重复率**: 重复数据检测和处理率
- 目标: <5%
- 当前: ~8-12%
### 7.2 资源使用监控
#### 7.2.1 内存监控
```python
def get_memory_metrics():
process = psutil.Process()
return {
'memory_usage_mb': process.memory_info().rss / 1024 / 1024,
'memory_percent': process.memory_percent(),
'queue_size': optimizer.batch_queue.qsize(),
'processed_keys_count': len(optimizer.processed_keys)
}
```
#### 7.2.2 数据库连接监控
```sql
-- 监控数据库连接状态
SELECT
VARIABLE_NAME,
VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Threads_connected',
'Threads_running',
'Questions',
'Queries'
);
```
### 7.3 告警规则
#### 7.3.1 性能告警
- 批处理队列大小 > 1000 (5分钟内)
- 平均处理时间 > 5秒 (5分钟内)
- 错误率 > 1% (10分钟内)
- 内存使用率 > 80% (持续5分钟)
#### 7.3.2 可用性告警
- 批处理器停止运行
- 数据库连接失败
- Redis连接失败
- 线程池异常退出
### 7.4 监控面板
建议在Grafana中创建专门的批处理监控面板,包含:
1. **实时处理指标**
- 每秒处理数据量 (时间序列图)
- 批处理队列大小 (实时计数器)
- 平均批处理时间 (时间序列图)
2. **错误和异常监控**
- 错误率趋势 (百分比图表)
- 重复数据率 (百分比图表)
- 异常类型分布 (饼图)
3. **资源使用监控**
- CPU使用率 (时间序列图)
- 内存使用率 (时间序列图)
- 数据库连接数 (时间序列图)
## 总结
通过以上优化方案的实施,预期可以实现:
1. **性能提升**: 整体处理性能提升150-300%
2. **可靠性增强**: 成功率提升至99.9%以上
3. **可扩展性**: 支持更高并发和数据量
4. **可观测性**: 完善的监控和告警体系
5. **可维护性**: 更清晰的代码结构和错误处理
建议按照优先级分阶段实施,先实现高优先级的优化项获得快速收益,再逐步完善中低优先级的改进项。