SpringBoot + 规则执行性能监控 + 耗时告警:慢规则自动识别,避免拖垮核心链路
问题背景
在现代业务系统中,规则引擎扮演着越来越重要的角色。无论是电商平台的促销规则、风控系统的风控规则,还是推荐系统的推荐规则,规则引擎都在核心业务链路中发挥着关键作用。然而,规则执行的性能问题往往被忽视,直到系统出现故障才引起重视。
常见的规则性能问题包括:
- 规则执行耗时过长:某些规则由于逻辑复杂或数据量大,执行时间远超预期
- 规则执行频率过高:高频执行的规则消耗大量系统资源
- 规则执行异常:规则执行过程中出现异常,导致系统不稳定
- 缺乏监控手段:无法及时发现规则性能问题,被动应对故障
- 影响核心链路:慢规则拖垮整个系统,影响用户体验
这些问题在业务高峰期尤为突出,可能导致系统响应变慢、服务不可用,甚至引发级联故障。如何及时发现和解决规则性能问题,保障核心链路的稳定性,是业务系统面临的重要挑战。
核心概念
1. 规则执行性能监控
定义:对规则执行的过程进行实时监控,收集规则执行的关键指标,包括执行时间、执行频率、执行结果等。
监控指标:
- 执行时间:规则执行的总耗时,包括条件判断时间和动作执行时间
- 执行频率:单位时间内规则执行的次数
- 执行结果:规则执行的成功率和失败率
- 资源消耗:规则执行过程中的CPU、内存、IO等资源消耗
2. 耗时告警
定义:当规则执行时间超过预设阈值时,自动触发告警通知,提醒相关人员及时处理。
告警策略:
- 阈值告警:当单次执行时间超过阈值时触发告警
- 频率告警:当单位时间内慢规则次数超过阈值时触发告警
- 趋势告警:当规则执行时间呈上升趋势时触发告警
- 对比告警:当规则执行时间较历史同期明显增加时触发告警
3. 慢规则识别
定义:通过分析规则执行数据,自动识别执行耗时的规则,并进行分类和排序。
识别方法:
- 基于阈值:执行时间超过预设阈值的规则
- 基于百分位:执行时间超过P95、P99等百分位的规则
- 基于趋势:执行时间呈上升趋势的规则
- 基于影响:对系统性能影响最大的规则
4. 性能优化
定义:针对识别出的慢规则,进行性能优化,降低规则执行时间,提升系统性能。
优化策略:
- 规则重构:优化规则逻辑,减少不必要的计算
- 数据优化:优化数据查询,减少IO操作
- 缓存优化:使用缓存减少重复计算
- 并行执行:将规则拆分为多个子任务并行执行
- 异步执行:将非关键规则改为异步执行
实现方案
1. 技术栈选择
- Spring Boot 2.7.5:提供基础框架支持
- Spring AOP:实现规则执行的切面监控
- Spring Data JPA:操作数据库
- MySQL 8.0:存储规则执行日志和性能数据
- Micrometer:性能指标收集
- Prometheus:性能指标存储和查询
- Grafana:性能指标可视化
- 邮件/钉钉/企业微信:告警通知渠道
2. 数据库设计
规则执行日志表(rule_execution_log)
| 字段名 | 数据类型 | 描述 |
|---|---|---|
| id | bigint(20) | 主键ID |
| rule_id | varchar(100) | 规则ID |
| rule_name | varchar(255) | 规则名称 |
| execution_time | bigint(20) | 执行时间(毫秒) |
| execution_result | tinyint(4) | 执行结果:0-失败,1-成功 |
| error_message | text | 错误信息 |
| input_data | text | 输入数据(JSON格式) |
| output_data | text | 输出数据(JSON格式) |
| create_time | datetime | 创建时间 |
规则性能统计表(rule_performance_stats)
| 字段名 | 数据类型 | 描述 |
|---|---|---|
| id | bigint(20) | 主键ID |
| rule_id | varchar(100) | 规则ID |
| stats_date | date | 统计日期 |
| execution_count | bigint(20) | 执行次数 |
| avg_execution_time | bigint(20) | 平均执行时间(毫秒) |
| max_execution_time | bigint(20) | 最大执行时间(毫秒) |
| min_execution_time | bigint(20) | 最小执行时间(毫秒) |
| p50_execution_time | bigint(20) | P50执行时间(毫秒) |
| p95_execution_time | bigint(20) | P95执行时间(毫秒) |
| p99_execution_time | bigint(20) | P99执行时间(毫秒) |
| slow_count | bigint(20) | 慢规则次数 |
| error_count | bigint(20) | 错误次数 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
告警配置表(alert_config)
| 字段名 | 数据类型 | 描述 |
|---|---|---|
| id | bigint(20) | 主键ID |
| rule_id | varchar(100) | 规则ID(为空表示全局配置) |
| alert_type | tinyint(4) | 告警类型:1-阈值告警,2-频率告警,3-趋势告警 |
| threshold | bigint(20) | 阈值(毫秒或次数) |
| time_window | int(11) | 时间窗口(分钟) |
| alert_channels | varchar(500) | 告警渠道(JSON格式) |
| status | tinyint(4) | 状态:0-禁用,1-启用 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
3. 核心代码实现
3.1 规则执行切面
使用Spring AOP实现规则执行的切面监控,收集规则执行的关键指标。
@Aspect
@Component
public class RuleExecutionAspect {
private static final Logger log = LoggerFactory.getLogger(RuleExecutionAspect.class);
@Autowired
private RuleExecutionLogRepository ruleExecutionLogRepository;
@Autowired
private RulePerformanceMonitor rulePerformanceMonitor;
@Autowired
private AlertService alertService;
/**
* 规则执行切面
*/
@Around("@annotation(com.example.demo.annotation.RuleExecution)")
public Object aroundRuleExecution(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取规则信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RuleExecution ruleExecution = method.getAnnotation(RuleExecution.class);
String ruleId = ruleExecution.ruleId();
String ruleName = ruleExecution.ruleName();
// 记录开始时间
long startTime = System.currentTimeMillis();
// 记录输入数据
Object[] args = joinPoint.getArgs();
String inputData = serializeInputData(args);
Object result = null;
boolean success = true;
String errorMessage = null;
try {
// 执行规则
result = joinPoint.proceed();
} catch (Exception e) {
success = false;
errorMessage = e.getMessage();
log.error("规则执行失败:{} - {}", ruleId, ruleName, e);
throw e;
} finally {
// 记录结束时间
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
// 记录输出数据
String outputData = serializeOutputData(result);
// 保存执行日志
RuleExecutionLog executionLog = new RuleExecutionLog();
executionLog.setRuleId(ruleId);
executionLog.setRuleName(ruleName);
executionLog.setExecutionTime(executionTime);
executionLog.setExecutionResult(success ? 1 : 0);
executionLog.setErrorMessage(errorMessage);
executionLog.setInputData(inputData);
executionLog.setOutputData(outputData);
ruleExecutionLogRepository.save(executionLog);
// 更新性能统计
rulePerformanceMonitor.updatePerformanceStats(ruleId, executionTime, success);
// 检查是否需要告警
alertService.checkAndAlert(ruleId, ruleName, executionTime, success);
log.info("规则执行完成:{} - {},耗时:{}ms,结果:{}",
ruleId, ruleName, executionTime, success ? "成功" : "失败");
}
return result;
}
/**
* 序列化输入数据
*/
private String serializeInputData(Object[] args) {
try {
return new ObjectMapper().writeValueAsString(args);
} catch (Exception e) {
log.error("序列化输入数据失败", e);
return null;
}
}
/**
* 序列化输出数据
*/
private String serializeOutputData(Object result) {
try {
return new ObjectMapper().writeValueAsString(result);
} catch (Exception e) {
log.error("序列化输出数据失败", e);
return null;
}
}
}
3.2 规则性能监控服务
实现规则性能监控服务,收集和分析规则执行数据。
@Service
public class RulePerformanceMonitor {
private static final Logger log = LoggerFactory.getLogger(RulePerformanceMonitor.class);
@Autowired
private RulePerformanceStatsRepository rulePerformanceStatsRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String STATS_KEY_PREFIX = "rule:stats:";
private static final String EXECUTION_TIMES_KEY_PREFIX = "rule:execution_times:";
/**
* 更新性能统计
*/
public void updatePerformanceStats(String ruleId, long executionTime, boolean success) {
try {
String today = LocalDate.now().toString();
String statsKey = STATS_KEY_PREFIX + ruleId + ":" + today;
String executionTimesKey = EXECUTION_TIMES_KEY_PREFIX + ruleId + ":" + today;
// 更新执行次数
redisTemplate.opsForHash().increment(statsKey, "execution_count", 1);
// 更新执行时间列表
redisTemplate.opsForList().rightPush(executionTimesKey, executionTime);
// 更新最大执行时间
Object maxTime = redisTemplate.opsForHash().get(statsKey, "max_execution_time");
if (maxTime == null || executionTime > (Long) maxTime) {
redisTemplate.opsForHash().put(statsKey, "max_execution_time", executionTime);
}
// 更新最小执行时间
Object minTime = redisTemplate.opsForHash().get(statsKey, "min_execution_time");
if (minTime == null || executionTime < (Long) minTime) {
redisTemplate.opsForHash().put(statsKey, "min_execution_time", executionTime);
}
// 更新慢规则次数
if (executionTime > 1000) { // 假设1秒以上为慢规则
redisTemplate.opsForHash().increment(statsKey, "slow_count", 1);
}
// 更新错误次数
if (!success) {
redisTemplate.opsForHash().increment(statsKey, "error_count", 1);
}
// 设置过期时间
redisTemplate.expire(statsKey, 2, TimeUnit.DAYS);
redisTemplate.expire(executionTimesKey, 2, TimeUnit.DAYS);
} catch (Exception e) {
log.error("更新性能统计失败", e);
}
}
/**
* 获取规则性能统计
*/
public RulePerformanceStats getPerformanceStats(String ruleId, LocalDate statsDate) {
// 先从数据库查询
RulePerformanceStats stats = rulePerformanceStatsRepository
.findByRuleIdAndStatsDate(ruleId, statsDate);
if (stats != null) {
return stats;
}
// 从Redis查询并计算
String today = statsDate.toString();
String statsKey = STATS_KEY_PREFIX + ruleId + ":" + today;
String executionTimesKey = EXECUTION_TIMES_KEY_PREFIX + ruleId + ":" + today;
Map<Object, Object> statsMap = redisTemplate.opsForHash().entries(statsKey);
List<Object> executionTimes = redisTemplate.opsForList().range(executionTimesKey, 0, -1);
if (statsMap.isEmpty()) {
return null;
}
// 计算统计数据
stats = new RulePerformanceStats();
stats.setRuleId(ruleId);
stats.setStatsDate(statsDate);
stats.setExecutionCount((Long) statsMap.getOrDefault("execution_count", 0L));
stats.setMaxExecutionTime((Long) statsMap.getOrDefault("max_execution_time", 0L));
stats.setMinExecutionTime((Long) statsMap.getOrDefault("min_execution_time", 0L));
stats.setSlowCount((Long) statsMap.getOrDefault("slow_count", 0L));
stats.setErrorCount((Long) statsMap.getOrDefault("error_count", 0L));
// 计算百分位
if (executionTimes != null && !executionTimes.isEmpty()) {
List<Long> times = executionTimes.stream()
.map(obj -> (Long) obj)
.sorted()
.collect(Collectors.toList());
stats.setAvgExecutionTime(calculateAverage(times));
stats.setP50ExecutionTime(calculatePercentile(times, 0.5));
stats.setP95ExecutionTime(calculatePercentile(times, 0.95));
stats.setP99ExecutionTime(calculatePercentile(times, 0.99));
}
return stats;
}
/**
* 识别慢规则
*/
public List<RulePerformanceStats> identifySlowRules(LocalDate statsDate, long threshold) {
List<RulePerformanceStats> allStats = rulePerformanceStatsRepository
.findByStatsDateAndAvgExecutionTimeGreaterThan(statsDate, threshold);
// 按平均执行时间排序
return allStats.stream()
.sorted((a, b) -> Long.compare(b.getAvgExecutionTime(), a.getAvgExecutionTime()))
.collect(Collectors.toList());
}
/**
* 计算平均值
*/
private long calculateAverage(List<Long> times) {
if (times.isEmpty()) return 0;
long sum = times.stream().mapToLong(Long::longValue).sum();
return sum / times.size();
}
/**
* 计算百分位
*/
private long calculatePercentile(List<Long> times, double percentile) {
if (times.isEmpty()) return 0;
int index = (int) Math.ceil(times.size() * percentile) - 1;
return times.get(Math.max(0, index));
}
}
3.3 告警服务
实现告警服务,根据告警配置和规则执行情况,触发告警通知。
@Service
public class AlertService {
private static final Logger log = LoggerFactory.getLogger(AlertService.class);
@Autowired
private AlertConfigRepository alertConfigRepository;
@Autowired
private JavaMailSender mailSender;
@Autowired
private RestTemplate restTemplate;
/**
* 检查并触发告警
*/
public void checkAndAlert(String ruleId, String ruleName, long executionTime, boolean success) {
try {
// 查询规则告警配置
List<AlertConfig> alertConfigs = alertConfigRepository.findByRuleIdAndStatus(ruleId, 1);
// 查询全局告警配置
List<AlertConfig> globalConfigs = alertConfigRepository.findByRuleIdIsNullAndStatus(1);
alertConfigs.addAll(globalConfigs);
for (AlertConfig config : alertConfigs) {
boolean shouldAlert = false;
String alertMessage = null;
switch (config.getAlertType()) {
case 1: // 阈值告警
if (executionTime > config.getThreshold()) {
shouldAlert = true;
alertMessage = String.format("规则 [%s] 执行时间超过阈值,当前耗时:%d ms,阈值:%d ms",
ruleName, executionTime, config.getThreshold());
}
break;
case 2: // 频率告警
// 统计时间窗口内的慢规则次数
long slowCount = countSlowExecutions(ruleId, config.getTimeWindow(), config.getThreshold());
if (slowCount > config.getThreshold()) {
shouldAlert = true;
alertMessage = String.format("规则 [%s] 在 %d 分钟内慢规则次数超过阈值,当前次数:%d,阈值:%d",
ruleName, config.getTimeWindow(), slowCount, config.getThreshold());
}
break;
case 3: // 趋势告警
// 检查执行时间趋势
if (checkExecutionTimeTrend(ruleId, config.getTimeWindow())) {
shouldAlert = true;
alertMessage = String.format("规则 [%s] 执行时间呈上升趋势,请关注性能优化",
ruleName);
}
break;
}
if (shouldAlert) {
sendAlert(config, alertMessage);
}
}
} catch (Exception e) {
log.error("检查告警失败", e);
}
}
/**
* 发送告警
*/
private void sendAlert(AlertConfig config, String message) {
try {
List<String> channels = parseAlertChannels(config.getAlertChannels());
for (String channel : channels) {
switch (channel) {
case "email":
sendEmailAlert(message);
break;
case "dingtalk":
sendDingTalkAlert(message);
break;
case "wechat":
sendWeChatAlert(message);
break;
default:
log.warn("未知的告警渠道:{}", channel);
}
}
} catch (Exception e) {
log.error("发送告警失败", e);
}
}
/**
* 发送邮件告警
*/
private void sendEmailAlert(String message) {
try {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo("admin@example.com");
mailMessage.setSubject("规则执行性能告警");
mailMessage.setText(message);
mailSender.send(mailMessage);
log.info("邮件告警发送成功");
} catch (Exception e) {
log.error("邮件告警发送失败", e);
}
}
/**
* 发送钉钉告警
*/
private void sendDingTalkAlert(String message) {
try {
String webhookUrl = "https://oapi.dingtalk.com/robot/send?access_token=your_token";
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("msgtype", "text");
Map<String, String> text = new HashMap<>();
text.put("content", message);
requestBody.put("text", text);
restTemplate.postForObject(webhookUrl, requestBody, String.class);
log.info("钉钉告警发送成功");
} catch (Exception e) {
log.error("钉钉告警发送失败", e);
}
}
/**
* 发送企业微信告警
*/
private void sendWeChatAlert(String message) {
try {
String webhookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your_key";
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("msgtype", "text");
Map<String, String> text = new HashMap<>();
text.put("content", message);
requestBody.put("text", text);
restTemplate.postForObject(webhookUrl, requestBody, String.class);
log.info("企业微信告警发送成功");
} catch (Exception e) {
log.error("企业微信告警发送失败", e);
}
}
/**
* 统计慢规则执行次数
*/
private long countSlowExecutions(String ruleId, int timeWindow, long threshold) {
// 实现统计逻辑
// 这里简化处理,实际应该从数据库或Redis查询
return 0;
}
/**
* 检查执行时间趋势
*/
private boolean checkExecutionTimeTrend(String ruleId, int timeWindow) {
// 实现趋势检查逻辑
// 这里简化处理,实际应该比较历史数据
return false;
}
/**
* 解析告警渠道
*/
private List<String> parseAlertChannels(String alertChannels) {
try {
return new ObjectMapper().readValue(alertChannels, List.class);
} catch (Exception e) {
log.error("解析告警渠道失败", e);
return new ArrayList<>();
}
}
}
3.4 性能监控控制器
@RestController
@RequestMapping("/performance")
public class PerformanceController {
@Autowired
private RulePerformanceMonitor rulePerformanceMonitor;
@Autowired
private RuleExecutionLogRepository ruleExecutionLogRepository;
/**
* 获取规则性能统计
*/
@GetMapping("/{ruleId}/stats")
public ResponseEntity<Result> getPerformanceStats(
@PathVariable String ruleId,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) {
try {
if (date == null) {
date = LocalDate.now();
}
RulePerformanceStats stats = rulePerformanceMonitor.getPerformanceStats(ruleId, date);
return ResponseEntity.ok(Result.success(stats));
} catch (Exception e) {
log.error("获取性能统计失败", e);
return ResponseEntity.ok(Result.error("获取性能统计失败:" + e.getMessage()));
}
}
/**
* 获取慢规则列表
*/
@GetMapping("/slow-rules")
public ResponseEntity<Result> getSlowRules(
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@RequestParam(defaultValue = "1000") long threshold) {
try {
if (date == null) {
date = LocalDate.now();
}
List<RulePerformanceStats> slowRules = rulePerformanceMonitor.identifySlowRules(date, threshold);
return ResponseEntity.ok(Result.success(slowRules));
} catch (Exception e) {
log.error("获取慢规则列表失败", e);
return ResponseEntity.ok(Result.error("获取慢规则列表失败:" + e.getMessage()));
}
}
/**
* 获取规则执行日志
*/
@GetMapping("/{ruleId}/logs")
public ResponseEntity<Result> getExecutionLogs(
@PathVariable String ruleId,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "20") int size) {
try {
if (startTime == null) {
startTime = LocalDateTime.now().minusDays(1);
}
if (endTime == null) {
endTime = LocalDateTime.now();
}
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"));
Page<RuleExecutionLog> logs = ruleExecutionLogRepository
.findByRuleIdAndCreateTimeBetween(ruleId, startTime, endTime, pageable);
return ResponseEntity.ok(Result.success(logs));
} catch (Exception e) {
log.error("获取执行日志失败", e);
return ResponseEntity.ok(Result.error("获取执行日志失败:" + e.getMessage()));
}
}
// 其他方法:getPerformanceTrend、getAlertConfigs等
}
3.5 Web界面
提供直观的Web界面,展示规则性能监控数据和告警信息。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>规则性能监控</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script>
<style>
.metric-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
}
.metric-value {
font-size: 2rem;
font-weight: bold;
}
.metric-label {
font-size: 0.9rem;
opacity: 0.9;
}
.slow-rule-item {
border-left: 4px solid #dc3545;
padding-left: 15px;
margin-bottom: 15px;
}
.chart-container {
position: relative;
height: 300px;
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4">规则性能监控</h1>
<!-- 性能指标卡片 -->
<div class="row">
<div class="col-md-3">
<div class="metric-card">
<div class="metric-value" id="totalExecutions">0</div>
<div class="metric-label">总执行次数</div>
</div>
</div>
<div class="col-md-3">
<div class="metric-card">
<div class="metric-value" id="avgExecutionTime">0ms</div>
<div class="metric-label">平均执行时间</div>
</div>
</div>
<div class="col-md-3">
<div class="metric-card">
<div class="metric-value" id="slowRuleCount">0</div>
<div class="metric-label">慢规则数量</div>
</div>
</div>
<div class="col-md-3">
<div class="metric-card">
<div class="metric-value" id="errorRate">0%</div>
<div class="metric-label">错误率</div>
</div>
</div>
</div>
<!-- 性能趋势图表 -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">性能趋势</h5>
</div>
<div class="card-body">
<div class="chart-container">
<canvas id="performanceChart"></canvas>
</div>
</div>
</div>
<!-- 慢规则列表 -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">慢规则列表</h5>
</div>
<div class="card-body">
<div id="slowRulesList">
<!-- 慢规则列表将通过JavaScript动态生成 -->
</div>
</div>
</div>
<!-- 规则执行日志 -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">规则执行日志</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>规则ID</th>
<th>规则名称</th>
<th>执行时间</th>
<th>执行结果</th>
<th>创建时间</th>
</tr>
</thead>
<tbody id="executionLogsTable">
<!-- 执行日志将通过JavaScript动态生成 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
// 页面加载完成后加载数据
$(document).ready(function() {
loadPerformanceMetrics();
loadSlowRules();
loadExecutionLogs();
initPerformanceChart();
});
// 加载性能指标
function loadPerformanceMetrics() {
// 这里应该调用API获取性能指标
// 为了演示,使用模拟数据
$('#totalExecutions').text('12,345');
$('#avgExecutionTime').text('156ms');
$('#slowRuleCount').text('8');
$('#errorRate').text('0.5%');
}
// 加载慢规则列表
function loadSlowRules() {
$.ajax({
url: '/api/performance/slow-rules',
type: 'GET',
success: function(response) {
if (response.code === 200) {
var slowRules = response.data;
var container = $('#slowRulesList');
container.empty();
if (slowRules.length === 0) {
container.append('<div class="alert alert-info">暂无慢规则</div>');
return;
}
slowRules.forEach(function(rule) {
var item = '<div class="slow-rule-item">' +
'<h6>' + rule.ruleId + '</h6>' +
'<p class="mb-1">平均执行时间:' + rule.avgExecutionTime + 'ms</p>' +
'<p class="mb-1">最大执行时间:' + rule.maxExecutionTime + 'ms</p>' +
'<p class="mb-0 text-muted">执行次数:' + rule.executionCount + '</p>' +
'</div>';
container.append(item);
});
} else {
$('#slowRulesList').append('<div class="alert alert-danger">加载慢规则失败:' + response.message + '</div>');
}
},
error: function() {
$('#slowRulesList').append('<div class="alert alert-danger">加载慢规则失败</div>');
}
});
}
// 加载执行日志
function loadExecutionLogs() {
// 这里应该调用API获取执行日志
// 为了演示,使用模拟数据
var logs = [
{ruleId: 'rule_001', ruleName: '促销规则', executionTime: 120, executionResult: 1, createTime: '2024-01-15 10:30:00'},
{ruleId: 'rule_002', ruleName: '风控规则', executionTime: 80, executionResult: 1, createTime: '2024-01-15 10:29:00'},
{ruleId: 'rule_003', ruleName: '推荐规则', executionTime: 200, executionResult: 0, createTime: '2024-01-15 10:28:00'}
];
var tbody = $('#executionLogsTable');
tbody.empty();
logs.forEach(function(log) {
var resultText = log.executionResult === 1 ? '<span class="badge bg-success">成功</span>' : '<span class="badge bg-danger">失败</span>';
var row = '<tr>' +
'<td>' + log.ruleId + '</td>' +
'<td>' + log.ruleName + '</td>' +
'<td>' + log.executionTime + 'ms</td>' +
'<td>' + resultText + '</td>' +
'<td>' + log.createTime + '</td>' +
'</tr>';
tbody.append(row);
});
}
// 初始化性能趋势图表
function initPerformanceChart() {
var ctx = document.getElementById('performanceChart').getContext('2d');
// 模拟数据
var labels = ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'];
var data = [120, 135, 180, 220, 160, 140];
new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: '平均执行时间 (ms)',
data: data,
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: '执行时间 (ms)'
}
}
},
plugins: {
legend: {
display: true,
position: 'top'
}
}
}
});
}
</script>
</body>
</html>
最佳实践
1. 监控指标设计
- 核心指标:关注规则执行时间、执行频率、成功率等核心指标
- 业务指标:结合业务场景,设计业务相关的监控指标
- 系统指标:监控系统资源消耗,如CPU、内存、IO等
- 自定义指标:根据具体需求,设计自定义监控指标
2. 告警策略设计
- 合理阈值:根据历史数据和业务需求,设置合理的告警阈值
- 分级告警:根据严重程度,设计不同级别的告警
- 告警收敛:避免告警风暴,实现告警收敛
- 告警升级:长时间未处理的告警,自动升级通知
3. 性能优化策略
- 规则重构:优化规则逻辑,减少不必要的计算
- 数据优化:优化数据查询,减少IO操作
- 缓存优化:使用缓存减少重复计算
- 异步执行:将非关键规则改为异步执行
- 资源隔离:对资源消耗大的规则进行资源隔离
4. 监控体系设计
- 全链路监控:从规则触发到执行完成的完整链路监控
- 多维度监控:从时间、规则类型、业务场景等多维度监控
- 实时监控:实现秒级监控,及时发现问题
- 历史分析:保存历史数据,支持趋势分析和容量规划
5. 应急响应
- 预案准备:针对常见问题,准备应急预案
- 快速定位:通过监控数据,快速定位问题原因
- 快速回滚:建立快速回滚机制,降低故障影响
- 事后复盘:故障处理后,进行复盘和优化
总结与展望
总结
本方案通过SpringBoot + 规则执行性能监控 + 耗时告警的组合,实现了规则执行的全面监控和智能告警。主要优势包括:
- 全面监控:覆盖规则执行的各个环节,收集全面的性能数据
- 智能告警:支持多种告警策略,自动识别和通知性能问题
- 慢规则识别:自动识别慢规则,提供优化建议
- 可视化展示:直观的Web界面,便于查看和分析性能数据
- 降低风险:及时发现和解决性能问题,避免拖垮核心链路
展望
- AI智能分析:引入机器学习,智能分析规则性能趋势和异常
- 自动优化:基于性能数据,自动优化规则执行策略
- 全链路追踪:集成分布式追踪,实现全链路性能监控
- 智能预测:基于历史数据,预测规则性能趋势
- 自适应阈值:根据业务负载,动态调整告警阈值
结语
规则执行性能监控是保障业务系统稳定性的重要手段。通过本方案的实现,我们可以及时发现和解决规则性能问题,避免慢规则拖垮核心链路,提升系统的可靠性和用户体验。
希望本方案能够为您的项目提供参考,帮助您实现更加稳定、高效的规则管理系统。
公众号:服务端技术精选
如果您有任何问题或建议,欢迎在评论区留言讨论。
标题:SpringBoot + 规则执行性能监控 + 耗时告警:慢规则自动识别,避免拖垮核心链路
作者:jiangyi
地址:http://jiangyi.space/articles/2026/03/06/1772638611423.html
公众号:服务端技术精选
评论