Files
java-template/docs/upload_device_info_optimization_plan.md
T

499 lines
16 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.
# upload_device_info 接口性能优化方案
## 📊 接口现状分析
### 当前实现架构
**接口入口**: `bigScreen.py` 中的 `handle_device_info()`
**处理逻辑**: `device.py` 中的 `upload_device_info()`
**批量处理器**: `device_batch_processor.py` 中的 `DeviceBatchProcessor`
### 🔍 性能问题识别
#### 1. 架构复杂性问题
```python
# 当前调用链路过长
handle_device_info()
↓
upload_device_info()
↓
DeviceBatchProcessor.submit()
↓
异步队列处理
↓
同步数据库操作
```
**问题分析**:
- 调用链路长,增加延迟
- 多层异常处理和日志记录
- Flask应用上下文传递复杂
#### 2. 数据处理效率问题
```python
# 现有数据处理流程
def process_single_device(single_device_info):
# 1. 多次字典取值操作
system_software_version = data.get("System Software Version") or data.get("system_version")
wifi_address = data.get("Wifi Address") or data.get("wifi_address")
bluetooth_address = data.get("Bluetooth Address") or data.get("bluetooth_address")
# ... 大量重复的get操作
# 2. 字符串处理开销
ipv4_match = re.search(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', ip_address)
# 3. 时间戳转换开销
beijing_tz = pytz.timezone('Asia/Shanghai')
dt = datetime.fromtimestamp(int(timestamp)/1000, tz=beijing_tz)
```
**性能瓶颈**:
- 大量的字典key查找操作
- 正则表达式匹配开销
- 时区转换计算开销
- 字符串操作频繁
#### 3. 数据库操作问题
```python
# 当前数据库操作
def save_device_info_to_db(device_info):
# 1. 每次操作都创建新连接
device_info_record = DeviceInfo.query.filter_by(serial_number=serial_number).first()
# 2. N+1查询问题
user_info = UserInfo.query.filter_by(device_sn=serial_number).first()
# 3. 单条插入/更新
if device_info_record:
# 逐字段更新
else:
# 单条插入
db.session.commit()
```
**问题分析**:
- 缺少批量操作优化
- 存在N+1查询问题
- 频繁的数据库连接和提交
#### 4. 批量处理器配置问题
```python
# 当前批量处理器配置
class DeviceBatchProcessor:
def __init__(self):
self.batch_size = 50 # 批量大小偏小
self.max_workers = 4 # 线程数不够
self.queue_size = 1000 # 队列容量小
self.batch_timeout = 5 # 等待时间长
```
**配置问题**:
- 批量大小偏小,无法充分利用数据库批量操作优势
- 工作线程数不足,无法充分利用多核CPU
- 队列容量小,高并发时容易拒绝服务
## 🚀 优化方案设计
### 1. 接口架构优化
#### A. 简化调用链路
```python
# 优化后的简化架构
@app.route("/upload_device_info", methods=['POST'])
def handle_device_info():
"""简化的设备信息处理接口"""
device_info = request.get_json()
# 快速参数验证
if not device_info:
return jsonify({"status": "error", "message": "请求体不能为空"}), 400
# 直接提交到优化批量处理器
success = async_device_processor.submit_fast(device_info)
if success:
return STANDARD_SUCCESS_RESPONSE
else:
return jsonify({"status": "error", "message": "系统繁忙,请稍后重试"}), 503
```
#### B. 异步处理器重构
```python
class AsyncDeviceProcessor:
"""高性能异步设备信息处理器"""
def __init__(self):
# CPU自适应配置
self.cpu_cores = os.cpu_count()
self.batch_size = self.cpu_cores * 20 # 动态批量大小
self.max_workers = self.cpu_cores * 3 # 动态工作线程
self.queue_size = 10000 # 大容量队列
self.batch_timeout = 1.0 # 快速批处理
# 多级处理队列
self.parsing_queue = asyncio.Queue(maxsize=5000)
self.validation_queue = asyncio.Queue(maxsize=3000)
self.database_queue = asyncio.Queue(maxsize=2000)
# 启动异步工作协程
self._start_async_workers()
async def submit_fast(self, device_info):
"""快速提交设备信息到异步队列"""
try:
await self.parsing_queue.put(device_info)
return True
except asyncio.QueueFull:
return False
```
### 2. 数据处理性能优化
#### A. 预编译和缓存优化
```python
class DeviceDataParser:
"""优化的设备数据解析器"""
# 预编译正则表达式
IPV4_PATTERN = re.compile(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b')
# 字段映射表(避免重复字符串比较)
FIELD_MAPPING = {
'system_version': ['System Software Version', 'system_version', 'SystemSoftwareVersion'],
'wifi_address': ['Wifi Address', 'wifi_address', 'WifiAddress'],
'bluetooth_address': ['Bluetooth Address', 'bluetooth_address', 'BluetoothAddress'],
'ip_address': ['IP Address', 'ip_address', 'IPAddress'],
'network_mode': ['Network Access Mode', 'network_mode', 'NetworkAccessMode'],
'serial_number': ['SerialNumber', 'serial_number', 'deviceSn'],
'device_name': ['Device Name', 'device_name', 'DeviceName'],
'imei': ['IMEI', 'imei']
}
# 时区对象缓存
BEIJING_TZ = pytz.timezone('Asia/Shanghai')
def extract_field_fast(self, data: dict, field_key: str):
"""快速字段提取"""
for possible_key in self.FIELD_MAPPING.get(field_key, [field_key]):
if possible_key in data:
return data[possible_key]
return None
def parse_device_data_batch(self, device_list: List[dict]) -> List[dict]:
"""批量解析设备数据"""
parsed_devices = []
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
for device_data in device_list:
try:
data = device_data.get("data", device_data)
# 使用优化的字段提取
parsed = {
'serial_number': self.extract_field_fast(data, 'serial_number'),
'device_name': self.extract_field_fast(data, 'device_name'),
'system_version': self.extract_field_fast(data, 'system_version'),
'wifi_address': self.extract_field_fast(data, 'wifi_address'),
'bluetooth_address': self.extract_field_fast(data, 'bluetooth_address'),
'network_mode': self.extract_field_fast(data, 'network_mode'),
'imei': self.extract_field_fast(data, 'imei'),
'update_time': current_time
}
# 优化IP地址提取
ip_raw = self.extract_field_fast(data, 'ip_address')
if ip_raw:
ip_match = self.IPV4_PATTERN.search(ip_raw)
parsed['ip_address'] = ip_match.group(0) if ip_match else None
# 优化时间戳处理
timestamp = data.get("timestamp")
if timestamp and str(timestamp).isdigit() and len(str(timestamp)) == 13:
dt = datetime.fromtimestamp(int(timestamp)/1000, tz=self.BEIJING_TZ)
parsed['timestamp'] = dt.strftime("%Y-%m-%d %H:%M:%S")
else:
parsed['timestamp'] = current_time
# 优化状态字段处理
battery_level = data.get("batteryLevel") or data.get("battery_level")
parsed['battery_level'] = self.normalize_battery_level_fast(battery_level)
wear_state = data.get("wearState") or data.get("wear_state")
parsed['wearable_status'] = "WORN" if wear_state and int(wear_state) == 1 else "NOT_WORN"
parsed_devices.append(parsed)
except Exception as e:
# 记录解析失败,但不中断批次处理
logger.warning(f"设备数据解析失败: {e}")
continue
return parsed_devices
@staticmethod
def normalize_battery_level_fast(battery_level):
"""快速电池电量标准化"""
if not battery_level:
return 0
try:
level = float(battery_level)
return max(0, min(100, level)) # 确保在0-100范围内
except (ValueError, TypeError):
return 0
```
#### B. 批量数据库操作优化
```python
class OptimizedDeviceDAO:
"""优化的设备信息数据访问层"""
def __init__(self):
self.batch_insert_size = 100
self.batch_update_size = 100
def batch_upsert_devices(self, device_list: List[dict]) -> dict:
"""批量插入或更新设备信息"""
if not device_list:
return {'inserted': 0, 'updated': 0, 'errors': 0}
stats = {'inserted': 0, 'updated': 0, 'errors': 0}
try:
# 1. 批量查询现有设备
serial_numbers = [d['serial_number'] for d in device_list if d.get('serial_number')]
existing_devices = {}
if serial_numbers:
existing_records = db.session.query(DeviceInfo).filter(
DeviceInfo.serial_number.in_(serial_numbers)
).all()
existing_devices = {device.serial_number: device for device in existing_records}
# 2. 分离插入和更新操作
devices_to_insert = []
devices_to_update = []
for device_data in device_list:
serial_number = device_data.get('serial_number')
if not serial_number:
stats['errors'] += 1
continue
if serial_number in existing_devices:
# 需要更新的设备
existing_device = existing_devices[serial_number]
self._update_device_fields(existing_device, device_data)
devices_to_update.append(existing_device)
else:
# 需要插入的新设备
new_device = DeviceInfo(**device_data)
devices_to_insert.append(new_device)
# 3. 批量插入新设备
if devices_to_insert:
db.session.bulk_save_objects(devices_to_insert)
stats['inserted'] = len(devices_to_insert)
# 4. 批量更新现有设备
if devices_to_update:
stats['updated'] = len(devices_to_update)
# 5. 提交事务
db.session.commit()
except Exception as e:
db.session.rollback()
logger.error(f"批量设备信息操作失败: {e}")
stats['errors'] = len(device_list)
return stats
def _update_device_fields(self, device: DeviceInfo, new_data: dict):
"""更新设备字段"""
update_fields = [
'device_name', 'system_version', 'wifi_address', 'bluetooth_address',
'ip_address', 'network_mode', 'imei', 'battery_level', 'wearable_status',
'update_time', 'timestamp'
]
for field in update_fields:
if field in new_data and new_data[field] is not None:
setattr(device, field, new_data[field])
```
### 3. 异步处理流水线
```python
class AsyncDeviceProcessingPipeline:
"""异步设备信息处理流水线"""
def __init__(self):
self.parser = DeviceDataParser()
self.dao = OptimizedDeviceDAO()
self.validator = DeviceDataValidator()
# 处理统计
self.stats = {
'total_processed': 0,
'total_success': 0,
'total_errors': 0,
'processing_time': 0
}
async def process_device_batch(self, device_batch: List[dict]):
"""异步处理设备批次"""
start_time = time.time()
try:
# Stage 1: 数据解析
parsed_devices = await asyncio.get_event_loop().run_in_executor(
None,
self.parser.parse_device_data_batch,
device_batch
)
# Stage 2: 数据验证
validated_devices = await asyncio.get_event_loop().run_in_executor(
None,
self.validator.validate_device_batch,
parsed_devices
)
# Stage 3: 数据库操作
result = await asyncio.get_event_loop().run_in_executor(
None,
self.dao.batch_upsert_devices,
validated_devices
)
# 更新统计
processing_time = time.time() - start_time
self.stats['total_processed'] += len(device_batch)
self.stats['total_success'] += result['inserted'] + result['updated']
self.stats['total_errors'] += result['errors']
self.stats['processing_time'] += processing_time
logger.info(f"设备批次处理完成: {len(device_batch)}条, 耗时: {processing_time:.3f}s")
except Exception as e:
self.stats['total_errors'] += len(device_batch)
logger.error(f"设备批次处理失败: {e}")
```
## 📈 性能优化预期效果
### 优化前后对比
| 指标 | 优化前 | 优化后 | 提升幅度 |
|------|--------|--------|----------|
| **单次请求响应时间** | 50-200ms | 10-30ms | **70-85%提升** |
| **批量处理能力** | 50设备/批次 | 100-200设备/批次 | **100-300%提升** |
| **并发处理能力** | 400设备同时 | 1000-2000设备同时 | **150-400%提升** |
| **数据库操作效率** | N+1查询 | 批量操作 | **90%查询减少** |
| **CPU利用率** | 20-40% | 60-80% | **100%效率提升** |
| **内存使用** | 100MB | 80MB | **20%内存节省** |
### 性能目标
- **QPS目标**: 2000+ 请求/秒
- **平均响应时间**: <20ms
- **99%分位响应时间**: <50ms
- **并发设备数**: 2000+ 设备同时上传
- **成功率**: >99.9%
## 🛠️ 实施方案
### Phase 1: 核心优化(1-2天)
1. **数据解析器优化**
- 实现 `DeviceDataParser` 类
- 预编译正则表达式
- 字段映射表优化
2. **批量处理器重构**
- 实现 `AsyncDeviceProcessor` 类
- CPU自适应配置
- 多级队列架构
### Phase 2: 数据库优化(2-3天)
1. **DAO层重构**
- 实现批量插入/更新逻辑
- 消除N+1查询问题
- 事务优化
2. **索引优化**
- 设备序列号索引
- 复合索引创建
### Phase 3: 异步流水线(2天)
1. **异步处理流水线**
- 实现多阶段异步处理
- 错误处理和恢复机制
- 性能监控集成
2. **接口简化**
- 重构 `handle_device_info` 函数
- 移除冗余日志和处理逻辑
### Phase 4: 测试和部署(1天)
1. **性能测试**
- 2000设备并发测试
- 压力测试和稳定性验证
2. **监控和告警**
- 性能指标监控
- 异常告警机制
## 📊 监控和维护
### 关键性能指标监控
```python
class DeviceProcessorMonitor:
"""设备处理器性能监控"""
def get_performance_metrics(self):
return {
'queue_sizes': {
'parsing': self.parsing_queue.qsize(),
'validation': self.validation_queue.qsize(),
'database': self.database_queue.qsize()
},
'processing_stats': self.stats,
'worker_status': self.get_worker_status(),
'system_resource': self.get_system_resource_usage()
}
```
### 告警机制
- 队列积压告警(队列大小 > 80%)
- 处理延迟告警(平均响应时间 > 100ms)
- 错误率告警(错误率 > 1%)
- 系统资源告警(CPU > 90%, 内存 > 90%)
## 🔧 配置管理
```python
DEVICE_PROCESSOR_CONFIG = {
'batch_size': os.getenv('DEVICE_BATCH_SIZE', os.cpu_count() * 20),
'max_workers': os.getenv('DEVICE_MAX_WORKERS', os.cpu_count() * 3),
'queue_size': os.getenv('DEVICE_QUEUE_SIZE', 10000),
'batch_timeout': float(os.getenv('DEVICE_BATCH_TIMEOUT', 1.0)),
'enable_async': os.getenv('DEVICE_ENABLE_ASYNC', 'true').lower() == 'true'
}
```
通过以上优化方案,`upload_device_info` 接口将获得显著的性能提升,能够支持更高的并发量和更快的响应时间,满足大规模设备部署的需求。