数据库修复: - 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]>
26 KiB
26 KiB
告警规则系统综合优化方案
📊 现状分析
当前t_alert_rules表结构
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;
当前系统痛点
- 单体征规则限制 - 当前每条规则只能配置单个
physical_sign - 复合条件缺失 - 无法实现"心率>120 AND 血氧<90"这类多体征关联告警
- 阈值表达能力有限 - 只支持min/max范围,无法支持复杂阈值逻辑
- 连续异常判断不灵活 - 只有简单的
trend_duration计数,缺乏时间窗口概念 - 高并发处理瓶颈 - 每次告警检测都需要查询数据库
🎯 核心需求分析
业务场景支持
场景1:单体征阈值告警
- 需求: 心率高于120连续3次触发告警
- 当前: ✅ 已支持
- 优化: 增强时间窗口控制
场景2:多体征关联告警
- 需求: 心率>120 AND 血氧<90 同时满足时触发告警
- 当前: ❌ 不支持
- 优化: 新增复合规则支持
场景3:复杂阈值条件
- 需求: 心率异常=(心率>最大阈值 OR 心率<最小阈值)AND 持续时间>5分钟
- 当前: ❌ 部分支持
- 优化: 增强条件表达式引擎
场景4:智能告警抑制
- 需求: 避免短时间内重复告警
- 当前: ❌ 无抑制机制
- 优化: 添加告警去重和抑制逻辑
🚀 优化方案设计
1. 数据结构优化
1.1 保持向下兼容的表结构增强
-- 在现有表基础上增加字段,保持向下兼容
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 复合规则条件表达式设计
{
"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 规则处理引擎设计
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 规则管理页面结构
// 前端界面设计 - 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 规则配置向导组件
<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 三层缓存架构
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 规则预编译与索引优化
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 异步处理与批量优化
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 测试指标设计
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周)
- 数据库表结构增强 - 添加新字段,保持现有功能不变
- 缓存机制优化 - 实现三层缓存架构
- 性能基准测试 - 建立性能监控基线
阶段二:复合规则支持 (3周)
- 规则引擎开发 - 支持多体征关联告警
- 管理界面开发 - 可视化规则配置向导
- 规则编译器 - 预编译优化执行效率
阶段三:高并发优化 (2周)
- 异步处理架构 - 批量处理和异步队列
- 告警抑制机制 - 避免重复告警
- 性能调优 - 达到目标性能指标
阶段四:生产部署 (1周)
- 灰度发布 - 逐步替换现有系统
- 监控告警 - 建立系统监控
- 文档完善 - 用户手册和运维文档
🎯 预期效果
性能提升
- 规则评估速度: 提升80%以上 (缓存优化)
- 并发处理能力: 支持10倍以上并发 (异步架构)
- 内存使用: 减少40% (规则预编译)
功能增强
- 规则表达能力: 支持复杂的多体征关联告警
- 管理易用性: 可视化配置界面,降低使用门槛
- 系统稳定性: 告警抑制和冷却机制避免告警风暴
业务价值
- 告警准确性: 减少80%以上误报 (复合条件)
- 响应速度: 告警延迟降低到秒级
- 运维成本: 减少50%以上人工干预
这个方案在保持系统稳定性的前提下,逐步提升告警规则的表达能力和处理性能,满足复杂业务场景的需求。