SpringBoot + 规则执行性能监控 + 耗时告警:慢规则自动识别,避免拖垮核心链路

问题背景

在现代业务系统中,规则引擎扮演着越来越重要的角色。无论是电商平台的促销规则、风控系统的风控规则,还是推荐系统的推荐规则,规则引擎都在核心业务链路中发挥着关键作用。然而,规则执行的性能问题往往被忽视,直到系统出现故障才引起重视。

常见的规则性能问题包括:

  1. 规则执行耗时过长:某些规则由于逻辑复杂或数据量大,执行时间远超预期
  2. 规则执行频率过高:高频执行的规则消耗大量系统资源
  3. 规则执行异常:规则执行过程中出现异常,导致系统不稳定
  4. 缺乏监控手段:无法及时发现规则性能问题,被动应对故障
  5. 影响核心链路:慢规则拖垮整个系统,影响用户体验

这些问题在业务高峰期尤为突出,可能导致系统响应变慢、服务不可用,甚至引发级联故障。如何及时发现和解决规则性能问题,保障核心链路的稳定性,是业务系统面临的重要挑战。

核心概念

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)

字段名数据类型描述
idbigint(20)主键ID
rule_idvarchar(100)规则ID
rule_namevarchar(255)规则名称
execution_timebigint(20)执行时间(毫秒)
execution_resulttinyint(4)执行结果:0-失败,1-成功
error_messagetext错误信息
input_datatext输入数据(JSON格式)
output_datatext输出数据(JSON格式)
create_timedatetime创建时间

规则性能统计表(rule_performance_stats)

字段名数据类型描述
idbigint(20)主键ID
rule_idvarchar(100)规则ID
stats_datedate统计日期
execution_countbigint(20)执行次数
avg_execution_timebigint(20)平均执行时间(毫秒)
max_execution_timebigint(20)最大执行时间(毫秒)
min_execution_timebigint(20)最小执行时间(毫秒)
p50_execution_timebigint(20)P50执行时间(毫秒)
p95_execution_timebigint(20)P95执行时间(毫秒)
p99_execution_timebigint(20)P99执行时间(毫秒)
slow_countbigint(20)慢规则次数
error_countbigint(20)错误次数
create_timedatetime创建时间
update_timedatetime更新时间

告警配置表(alert_config)

字段名数据类型描述
idbigint(20)主键ID
rule_idvarchar(100)规则ID(为空表示全局配置)
alert_typetinyint(4)告警类型:1-阈值告警,2-频率告警,3-趋势告警
thresholdbigint(20)阈值(毫秒或次数)
time_windowint(11)时间窗口(分钟)
alert_channelsvarchar(500)告警渠道(JSON格式)
statustinyint(4)状态:0-禁用,1-启用
create_timedatetime创建时间
update_timedatetime更新时间

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 + 规则执行性能监控 + 耗时告警的组合,实现了规则执行的全面监控和智能告警。主要优势包括:

  1. 全面监控:覆盖规则执行的各个环节,收集全面的性能数据
  2. 智能告警:支持多种告警策略,自动识别和通知性能问题
  3. 慢规则识别:自动识别慢规则,提供优化建议
  4. 可视化展示:直观的Web界面,便于查看和分析性能数据
  5. 降低风险:及时发现和解决性能问题,避免拖垮核心链路

展望

  1. AI智能分析:引入机器学习,智能分析规则性能趋势和异常
  2. 自动优化:基于性能数据,自动优化规则执行策略
  3. 全链路追踪:集成分布式追踪,实现全链路性能监控
  4. 智能预测:基于历史数据,预测规则性能趋势
  5. 自适应阈值:根据业务负载,动态调整告警阈值

结语

规则执行性能监控是保障业务系统稳定性的重要手段。通过本方案的实现,我们可以及时发现和解决规则性能问题,避免慢规则拖垮核心链路,提升系统的可靠性和用户体验。

希望本方案能够为您的项目提供参考,帮助您实现更加稳定、高效的规则管理系统。


公众号:服务端技术精选

如果您有任何问题或建议,欢迎在评论区留言讨论。


标题:SpringBoot + 规则执行性能监控 + 耗时告警:慢规则自动识别,避免拖垮核心链路
作者:jiangyi
地址:http://jiangyi.space/articles/2026/03/06/1772638611423.html
公众号:服务端技术精选
    评论
    0 评论
avatar

取消