Files
java-template/docs/alert_rules_optimization_comprehensive_solution.md
T
BrunoGaoandClaude e402548e45 fix: 修复customer_id字段缺失问题,完成数据库schema同步
数据库修复:
- t_user_health_data_daily: 添加customer_id字段(租户ID)
- t_user_health_data_weekly: 添加customer_id字段(租户ID)

ljwx-boot同步更新:
- TUserHealthDataDailyMapper.xml: 添加customer_id字段映射
- TUserHealthDataWeeklyMapper.xml: 添加customer_id字段映射

其他改进:
- 告警规则缓存优化
- Redis缓存性能提升
- 健康数据处理性能优化
- 添加完整的文档和工具脚本

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

Co-Authored-By: Claude <[email protected]>
2025-09-10 13:49:59 +08:00

710 lines
26 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.
# 告警规则系统综合优化方案
## 📊 现状分析
### 当前t_alert_rules表结构
```sql
CREATE TABLE `t_alert_rules` (
`id` bigint NOT NULL AUTO_INCREMENT,
`rule_type` varchar(50) NOT NULL DEFAULT 'metric' COMMENT 'metric|custom|fallback',
`physical_sign` varchar(50) DEFAULT NULL,
`threshold_min` decimal(10,2) DEFAULT NULL,
`threshold_max` decimal(10,2) DEFAULT NULL,
`deviation_percentage` decimal(5,2) DEFAULT NULL,
`trend_duration` int DEFAULT NULL COMMENT '连续异常次数',
`parameters` json DEFAULT NULL,
`trigger_condition` text,
`alert_message` text,
`severity_level` varchar(20) DEFAULT NULL,
`notification_type` varchar(50) DEFAULT 'message',
`customer_id` bigint DEFAULT NULL,
`is_active` tinyint(1) DEFAULT 1,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_by` bigint DEFAULT NULL,
`updated_by` bigint DEFAULT NULL,
`deleted` tinyint(1) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```
### 当前系统痛点
1. **单体征规则限制** - 当前每条规则只能配置单个`physical_sign`
2. **复合条件缺失** - 无法实现"心率>120 AND 血氧<90"这类多体征关联告警
3. **阈值表达能力有限** - 只支持min/max范围,无法支持复杂阈值逻辑
4. **连续异常判断不灵活** - 只有简单的`trend_duration`计数,缺乏时间窗口概念
5. **高并发处理瓶颈** - 每次告警检测都需要查询数据库
## 🎯 核心需求分析
### 业务场景支持
#### 场景1:单体征阈值告警
- **需求**: 心率高于120连续3次触发告警
- **当前**: ✅ 已支持
- **优化**: 增强时间窗口控制
#### 场景2:多体征关联告警
- **需求**: 心率>120 AND 血氧<90 同时满足时触发告警
- **当前**: ❌ 不支持
- **优化**: 新增复合规则支持
#### 场景3:复杂阈值条件
- **需求**: 心率异常=(心率>最大阈值 OR 心率<最小阈值)AND 持续时间>5分钟
- **当前**: ❌ 部分支持
- **优化**: 增强条件表达式引擎
#### 场景4:智能告警抑制
- **需求**: 避免短时间内重复告警
- **当前**: ❌ 无抑制机制
- **优化**: 添加告警去重和抑制逻辑
## 🚀 优化方案设计
### 1. 数据结构优化
#### 1.1 保持向下兼容的表结构增强
```sql
-- 在现有表基础上增加字段,保持向下兼容
ALTER TABLE `t_alert_rules`
ADD COLUMN `rule_category` ENUM('SINGLE', 'COMPOSITE', 'COMPLEX') DEFAULT 'SINGLE' COMMENT '规则类型:单体征/复合/复杂',
ADD COLUMN `condition_expression` TEXT COMMENT 'JSON格式的复杂条件表达式',
ADD COLUMN `time_window_seconds` INT DEFAULT 300 COMMENT '时间窗口(秒)',
ADD COLUMN `cooldown_seconds` INT DEFAULT 600 COMMENT '告警冷却期(秒)',
ADD COLUMN `priority_level` INT DEFAULT 3 COMMENT '优先级(1-5,数字越小优先级越高)',
ADD COLUMN `rule_tags` JSON COMMENT '规则标签,便于分类管理',
ADD COLUMN `effective_time_start` TIME COMMENT '生效开始时间',
ADD COLUMN `effective_time_end` TIME COMMENT '生效结束时间',
ADD COLUMN `effective_days` VARCHAR(20) DEFAULT '1,2,3,4,5,6,7' COMMENT '生效星期(1-7)',
ADD INDEX idx_customer_category (`customer_id`, `rule_category`),
ADD INDEX idx_priority (`priority_level`),
ADD INDEX idx_physical_sign_active (`physical_sign`, `is_active`);
```
#### 1.2 复合规则条件表达式设计
```json
{
"rule_type": "composite",
"conditions": [
{
"physical_sign": "heart_rate",
"operator": ">",
"threshold": 120,
"duration_seconds": 180
},
{
"physical_sign": "blood_oxygen",
"operator": "<",
"threshold": 90,
"duration_seconds": 60
}
],
"logical_operator": "AND",
"evaluation_window": 300,
"trigger_threshold": {
"type": "percentage",
"value": 80
}
}
```
#### 1.3 规则处理引擎设计
```python
class AlertRuleEngine:
"""高性能告警规则引擎"""
def __init__(self):
self.redis = RedisHelper()
self.rule_cache = {}
self.evaluation_cache = {}
def evaluate_rules(self, health_data: dict, device_info: dict) -> List[dict]:
"""
高效规则评估主入口
Args:
health_data: 健康数据
device_info: 设备信息
Returns:
符合条件的告警列表
"""
customer_id = device_info.get('customer_id')
user_id = health_data.get('user_id')
device_sn = health_data.get('deviceSn')
# 1. 获取缓存的规则
rules = self._get_cached_rules(customer_id)
if not rules:
return []
triggered_alerts = []
# 2. 按优先级和类型分组处理
for rule in sorted(rules, key=lambda x: x.get('priority_level', 5)):
if not self._is_rule_effective(rule):
continue
# 3. 根据规则类型选择评估策略
if rule['rule_category'] == 'SINGLE':
alert = self._evaluate_single_rule(rule, health_data, device_info)
elif rule['rule_category'] == 'COMPOSITE':
alert = self._evaluate_composite_rule(rule, health_data, device_info)
elif rule['rule_category'] == 'COMPLEX':
alert = self._evaluate_complex_rule(rule, health_data, device_info)
else:
continue
if alert:
# 4. 告警抑制检查
if not self._is_suppressed(alert, rule):
triggered_alerts.append(alert)
# 5. 设置冷却期
self._set_cooldown(alert, rule)
return triggered_alerts
def _evaluate_single_rule(self, rule: dict, health_data: dict, device_info: dict) -> Optional[dict]:
"""单体征规则评估 - 兼容现有逻辑"""
physical_sign = rule.get('physical_sign')
if not physical_sign or physical_sign not in health_data:
return None
value = float(health_data[physical_sign])
threshold_min = rule.get('threshold_min')
threshold_max = rule.get('threshold_max')
# 阈值检查
is_abnormal = False
if threshold_min and value < threshold_min:
is_abnormal = True
elif threshold_max and value > threshold_max:
is_abnormal = True
if not is_abnormal:
return None
# 连续异常检查(优化后的逻辑)
trend_duration = rule.get('trend_duration', 1)
time_window = rule.get('time_window_seconds', 300)
if self._check_trend_duration(health_data, rule, trend_duration, time_window):
return self._create_alert(rule, health_data, device_info, {
'trigger_value': value,
'threshold_min': threshold_min,
'threshold_max': threshold_max
})
return None
def _evaluate_composite_rule(self, rule: dict, health_data: dict, device_info: dict) -> Optional[dict]:
"""复合规则评估 - 支持多体征关联"""
try:
condition_expr = rule.get('condition_expression')
if not condition_expr:
return None
conditions = condition_expr.get('conditions', [])
logical_op = condition_expr.get('logical_operator', 'AND')
condition_results = []
trigger_details = {}
for condition in conditions:
physical_sign = condition['physical_sign']
if physical_sign not in health_data:
condition_results.append(False)
continue
value = float(health_data[physical_sign])
operator = condition['operator']
threshold = condition['threshold']
duration = condition.get('duration_seconds', 60)
# 单个条件评估
condition_met = self._evaluate_condition(value, operator, threshold)
# 持续时间检查
if condition_met and duration > 0:
condition_met = self._check_duration_for_sign(
health_data, physical_sign, operator, threshold, duration
)
condition_results.append(condition_met)
if condition_met:
trigger_details[physical_sign] = {
'value': value,
'operator': operator,
'threshold': threshold
}
# 逻辑组合评估
if logical_op == 'AND':
final_result = all(condition_results)
elif logical_op == 'OR':
final_result = any(condition_results)
else:
final_result = False
if final_result:
return self._create_alert(rule, health_data, device_info, {
'composite_triggers': trigger_details,
'condition_results': condition_results
})
except Exception as e:
logger.error(f"复合规则评估失败: {e}")
return None
def _get_cached_rules(self, customer_id: int) -> List[dict]:
"""获取缓存的告警规则"""
cache_key = f"alert_rules:customer:{customer_id}"
# 先检查内存缓存
if cache_key in self.rule_cache:
cached_time, rules = self.rule_cache[cache_key]
if time.time() - cached_time < 300: # 5分钟内存缓存
return rules
# Redis缓存
cached_rules = self.redis.get_data(cache_key)
if cached_rules:
rules = json.loads(cached_rules)
self.rule_cache[cache_key] = (time.time(), rules)
return rules
# 数据库查询并缓存
rules = self._load_rules_from_db(customer_id)
# 缓存到Redis(24小时)
self.redis.set_data(cache_key, json.dumps(rules, default=str), expire=86400)
self.rule_cache[cache_key] = (time.time(), rules)
return rules
```
### 2. 管理界面设计
#### 2.1 规则管理页面结构
```typescript
// 前端界面设计 - Vue3 + Element Plus
interface AlertRuleConfig {
id?: number;
ruleName: string;
ruleCategory: 'SINGLE' | 'COMPOSITE' | 'COMPLEX';
ruleType: string;
priorityLevel: number;
// 单体征规则
physicalSign?: string;
thresholdMin?: number;
thresholdMax?: number;
trendDuration?: number;
// 复合规则
conditionExpression?: {
conditions: Array<{
physicalSign: string;
operator: '>' | '<' | '=' | '>=' | '<=';
threshold: number;
durationSeconds: number;
}>;
logicalOperator: 'AND' | 'OR';
evaluationWindow: number;
};
// 生效时间
effectiveTimeStart?: string;
effectiveTimeEnd?: string;
effectiveDays: string;
timeWindowSeconds: number;
cooldownSeconds: number;
// 告警配置
severityLevel: string;
alertMessage: string;
notificationType: string;
customerId: number;
isActive: boolean;
}
```
#### 2.2 规则配置向导组件
```vue
<template>
<div class="alert-rule-wizard">
<!-- 步骤导航 -->
<el-steps :active="currentStep" align-center>
<el-step title="规则类型" />
<el-step title="条件配置" />
<el-step title="告警设置" />
<el-step title="生效时间" />
<el-step title="预览确认" />
</el-steps>
<!-- 规则类型选择 -->
<div v-show="currentStep === 0" class="step-content">
<el-card header="选择规则类型">
<el-radio-group v-model="ruleConfig.ruleCategory" @change="onRuleCategoryChange">
<el-radio label="SINGLE" class="rule-type-radio">
<div class="rule-type-item">
<h3>单体征规则</h3>
<p>基于单个生理指标的阈值告警,如:心率 > 120</p>
</div>
</el-radio>
<el-radio label="COMPOSITE" class="rule-type-radio">
<div class="rule-type-item">
<h3>复合规则</h3>
<p>多个生理指标的组合条件,如:心率 > 120 且 血氧 < 90</p>
</div>
</el-radio>
<el-radio label="COMPLEX" class="rule-type-radio">
<div class="rule-type-item">
<h3>复杂规则</h3>
<p>高级逻辑表达式,支持自定义计算公式</p>
</div>
</el-radio>
</el-radio-group>
</el-card>
</div>
<!-- 单体征条件配置 -->
<div v-show="currentStep === 1 && ruleConfig.ruleCategory === 'SINGLE'" class="step-content">
<el-card header="单体征条件配置">
<el-form :model="ruleConfig" label-width="120px">
<el-form-item label="生理指标">
<el-select v-model="ruleConfig.physicalSign" placeholder="选择生理指标">
<el-option label="心率" value="heart_rate" />
<el-option label="血氧" value="blood_oxygen" />
<el-option label="体温" value="temperature" />
<el-option label="收缩压" value="pressure_high" />
<el-option label="舒张压" value="pressure_low" />
<el-option label="步数" value="step" />
</el-select>
</el-form-item>
<el-form-item label="正常范围">
<el-input-number v-model="ruleConfig.thresholdMin" placeholder="最小值" />
<span style="margin: 0 10px;">至</span>
<el-input-number v-model="ruleConfig.thresholdMax" placeholder="最大值" />
</el-form-item>
<el-form-item label="连续异常次数">
<el-input-number v-model="ruleConfig.trendDuration" :min="1" />
<span class="help-text">连续超出阈值多少次后触发告警</span>
</el-form-item>
<el-form-item label="时间窗口">
<el-input-number v-model="ruleConfig.timeWindowSeconds" :min="60" />
<span class="help-text">秒,在此时间窗口内统计异常次数</span>
</el-form-item>
</el-form>
</el-card>
</div>
<!-- 复合条件配置 -->
<div v-show="currentStep === 1 && ruleConfig.ruleCategory === 'COMPOSITE'" class="step-content">
<el-card header="复合条件配置">
<div class="composite-conditions">
<div v-for="(condition, index) in compositeConditions" :key="index" class="condition-item">
<el-select v-model="condition.physicalSign" placeholder="生理指标">
<el-option label="心率" value="heart_rate" />
<el-option label="血氧" value="blood_oxygen" />
<el-option label="体温" value="temperature" />
</el-select>
<el-select v-model="condition.operator" placeholder="运算符">
<el-option label="大于" value=">" />
<el-option label="小于" value="<" />
<el-option label="等于" value="=" />
<el-option label="大于等于" value=">=" />
<el-option label="小于等于" value="<=" />
</el-select>
<el-input-number v-model="condition.threshold" placeholder="阈值" />
<el-input-number v-model="condition.durationSeconds" placeholder="持续时间(秒)" />
<el-button @click="removeCondition(index)" type="danger" icon="el-icon-delete" circle />
</div>
<div class="condition-logic">
<el-radio-group v-model="logicalOperator">
<el-radio label="AND">并且(AND)</el-radio>
<el-radio label="OR">或者(OR)</el-radio>
</el-radio-group>
</div>
<el-button @click="addCondition" type="primary" icon="el-icon-plus">添加条件</el-button>
</div>
</el-card>
</div>
<!-- 实时预览 -->
<div class="rule-preview">
<el-card header="规则预览">
<div class="preview-content">
<p><strong>规则描述:</strong>{{ generateRuleDescription() }}</p>
<p><strong>触发逻辑:</strong>{{ generateTriggerLogic() }}</p>
</div>
</el-card>
</div>
<!-- 操作按钮 -->
<div class="wizard-actions">
<el-button @click="previousStep" :disabled="currentStep === 0">上一步</el-button>
<el-button @click="nextStep" type="primary" :disabled="!canNextStep">下一步</el-button>
<el-button @click="saveRule" type="success" v-show="currentStep === 4">保存规则</el-button>
</div>
</div>
</template>
```
### 3. 高并发优化策略
#### 3.1 三层缓存架构
```python
class CachedRuleEngine:
"""三层缓存的告警规则引擎"""
def __init__(self):
# L1: 应用内存缓存 (最快,容量小)
self.memory_cache = {} # 5分钟TTL,最热数据
# L2: Redis缓存 (快速,容量中等)
self.redis = RedisHelper() # 1小时TTL,常用数据
# L3: 数据库 (慢速,容量大)
# 通过上层缓存减少数据库访问
def get_rules_with_cache(self, customer_id: int) -> List[dict]:
"""三层缓存获取规则"""
cache_key = f"rules:c{customer_id}"
# L1: 内存缓存
if cache_key in self.memory_cache:
cached_time, rules = self.memory_cache[cache_key]
if time.time() - cached_time < 300: # 5分钟
return rules
# L2: Redis缓存
redis_key = f"alert_rules:customer:{customer_id}"
cached_rules = self.redis.get_data(redis_key)
if cached_rules:
rules = json.loads(cached_rules)
# 回填L1缓存
self.memory_cache[cache_key] = (time.time(), rules)
return rules
# L3: 数据库查询
rules = self._query_rules_from_db(customer_id)
# 回填缓存
self.redis.set_data(redis_key, json.dumps(rules, default=str), expire=3600)
self.memory_cache[cache_key] = (time.time(), rules)
return rules
```
#### 3.2 规则预编译与索引优化
```python
class RuleCompiler:
"""规则预编译器 - 将规则转换为高效的执行结构"""
def compile_rules(self, rules: List[dict]) -> dict:
"""编译规则为高效执行结构"""
compiled_rules = {
'single_rules': defaultdict(list), # 按physical_sign分组
'composite_rules': [], # 复合规则列表
'priority_index': defaultdict(list), # 按优先级索引
}
for rule in rules:
if not rule.get('is_active'):
continue
priority = rule.get('priority_level', 5)
if rule['rule_category'] == 'SINGLE':
physical_sign = rule.get('physical_sign')
if physical_sign:
compiled_rule = self._compile_single_rule(rule)
compiled_rules['single_rules'][physical_sign].append(compiled_rule)
compiled_rules['priority_index'][priority].append(compiled_rule)
elif rule['rule_category'] == 'COMPOSITE':
compiled_rule = self._compile_composite_rule(rule)
compiled_rules['composite_rules'].append(compiled_rule)
compiled_rules['priority_index'][priority].append(compiled_rule)
return compiled_rules
def _compile_single_rule(self, rule: dict) -> dict:
"""编译单体征规则为高效结构"""
return {
'rule_id': rule['id'],
'physical_sign': rule['physical_sign'],
'check_min': rule.get('threshold_min') is not None,
'check_max': rule.get('threshold_max') is not None,
'threshold_min': rule.get('threshold_min', 0),
'threshold_max': rule.get('threshold_max', float('inf')),
'trend_duration': rule.get('trend_duration', 1),
'time_window': rule.get('time_window_seconds', 300),
'severity': rule.get('severity_level', 'MEDIUM'),
'message_template': rule.get('alert_message', ''),
'cooldown': rule.get('cooldown_seconds', 600),
'priority': rule.get('priority_level', 5)
}
```
#### 3.3 异步处理与批量优化
```python
class AsyncAlertProcessor:
"""异步告警处理器"""
def __init__(self):
self.alert_queue = asyncio.Queue(maxsize=10000)
self.batch_size = 100
self.workers = []
async def start_workers(self, worker_count: int = 4):
"""启动异步工作者"""
for i in range(worker_count):
worker = asyncio.create_task(self._worker_loop(f"worker-{i}"))
self.workers.append(worker)
async def process_alerts_batch(self, health_data_batch: List[dict]):
"""批量处理告警"""
# 1. 按customer_id分组批次
customer_batches = defaultdict(list)
for data in health_data_batch:
customer_id = data.get('customer_id')
customer_batches[customer_id].append(data)
# 2. 并行处理每个客户的数据
tasks = []
for customer_id, customer_data in customer_batches.items():
task = self._process_customer_batch(customer_id, customer_data)
tasks.append(task)
await asyncio.gather(*tasks, return_exceptions=True)
async def _process_customer_batch(self, customer_id: int, health_data_list: List[dict]):
"""处理单个客户的健康数据批次"""
# 1. 批量获取规则(一次查询)
rules = await self._get_rules_async(customer_id)
if not rules:
return
# 2. 编译规则(一次编译)
compiled_rules = self.rule_compiler.compile_rules(rules)
# 3. 批量评估
alert_tasks = []
for health_data in health_data_list:
task = self._evaluate_single_data(health_data, compiled_rules)
alert_tasks.append(task)
results = await asyncio.gather(*alert_tasks, return_exceptions=True)
# 4. 批量保存告警
valid_alerts = [alert for alert in results if alert and not isinstance(alert, Exception)]
if valid_alerts:
await self._save_alerts_batch(valid_alerts)
```
### 4. 性能基准测试
#### 4.1 测试指标设计
```python
class PerformanceTestSuite:
"""告警规则系统性能测试套件"""
async def test_rule_evaluation_performance(self):
"""规则评估性能测试"""
test_scenarios = [
{
'name': '单体征规则-1000条',
'rule_count': 1000,
'rule_type': 'SINGLE',
'data_points': 10000
},
{
'name': '复合规则-500条',
'rule_count': 500,
'rule_type': 'COMPOSITE',
'data_points': 10000
},
{
'name': '混合规则-高并发',
'rule_count': 2000,
'rule_type': 'MIXED',
'data_points': 50000,
'concurrent_requests': 100
}
]
for scenario in test_scenarios:
start_time = time.time()
# 执行测试场景
await self._run_scenario(scenario)
end_time = time.time()
duration = end_time - start_time
# 计算性能指标
throughput = scenario['data_points'] / duration
avg_latency = duration / scenario['data_points'] * 1000
print(f"""
场景: {scenario['name']}
总耗时: {duration:.2f}s
吞吐量: {throughput:.0f} records/s
平均延迟: {avg_latency:.2f}ms
""")
```
## 📈 实施计划
### 阶段一:向下兼容增强 (2周)
1. **数据库表结构增强** - 添加新字段,保持现有功能不变
2. **缓存机制优化** - 实现三层缓存架构
3. **性能基准测试** - 建立性能监控基线
### 阶段二:复合规则支持 (3周)
1. **规则引擎开发** - 支持多体征关联告警
2. **管理界面开发** - 可视化规则配置向导
3. **规则编译器** - 预编译优化执行效率
### 阶段三:高并发优化 (2周)
1. **异步处理架构** - 批量处理和异步队列
2. **告警抑制机制** - 避免重复告警
3. **性能调优** - 达到目标性能指标
### 阶段四:生产部署 (1周)
1. **灰度发布** - 逐步替换现有系统
2. **监控告警** - 建立系统监控
3. **文档完善** - 用户手册和运维文档
## 🎯 预期效果
### 性能提升
- **规则评估速度**: 提升80%以上 (缓存优化)
- **并发处理能力**: 支持10倍以上并发 (异步架构)
- **内存使用**: 减少40% (规则预编译)
### 功能增强
- **规则表达能力**: 支持复杂的多体征关联告警
- **管理易用性**: 可视化配置界面,降低使用门槛
- **系统稳定性**: 告警抑制和冷却机制避免告警风暴
### 业务价值
- **告警准确性**: 减少80%以上误报 (复合条件)
- **响应速度**: 告警延迟降低到秒级
- **运维成本**: 减少50%以上人工干预
这个方案在保持系统稳定性的前提下,逐步提升告警规则的表达能力和处理性能,满足复杂业务场景的需求。