1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
| @Component @Slf4j public class TenantMonitoringService {
@Autowired private MeterRegistry meterRegistry;
@Autowired private RedisTemplate<String, Object> redisTemplate;
public void recordTenantAccess(String tenantId, String operation, long duration) { try { Counter.builder("tenant.access.count") .tag("tenant_id", tenantId) .tag("operation", operation) .register(meterRegistry) .increment();
Timer.builder("tenant.access.duration") .tag("tenant_id", tenantId) .tag("operation", operation) .register(meterRegistry) .record(duration, TimeUnit.MILLISECONDS);
String key = "tenant:metrics:" + tenantId + ":" + LocalDate.now().toString(); redisTemplate.opsForHash().increment(key, operation + ":count", 1); redisTemplate.opsForHash().increment(key, operation + ":duration", duration); redisTemplate.expire(key, Duration.ofDays(7));
} catch (Exception e) { log.error("记录租户访问指标失败: tenantId={}, operation={}", tenantId, operation, e); } }
public void recordTenantError(String tenantId, String operation, String errorType) { try { Counter.builder("tenant.error.count") .tag("tenant_id", tenantId) .tag("operation", operation) .tag("error_type", errorType) .register(meterRegistry) .increment();
String key = "tenant:errors:" + tenantId + ":" + LocalDate.now().toString(); redisTemplate.opsForHash().increment(key, operation + ":" + errorType, 1); redisTemplate.expire(key, Duration.ofDays(7));
} catch (Exception e) { log.error("记录租户错误指标失败: tenantId={}, operation={}", tenantId, operation, e); } }
public TenantPerformanceStats getTenantPerformanceStats(String tenantId, LocalDate date) { try { TenantPerformanceStats stats = new TenantPerformanceStats(); stats.setTenantId(tenantId); stats.setDate(date);
String metricsKey = "tenant:metrics:" + tenantId + ":" + date.toString(); Map<Object, Object> metrics = redisTemplate.opsForHash().entries(metricsKey);
String errorsKey = "tenant:errors:" + tenantId + ":" + date.toString(); Map<Object, Object> errors = redisTemplate.opsForHash().entries(errorsKey);
calculatePerformanceStats(stats, metrics, errors);
return stats;
} catch (Exception e) { log.error("获取租户性能统计失败: tenantId={}, date={}", tenantId, date, e); return new TenantPerformanceStats(); } }
private void calculatePerformanceStats(TenantPerformanceStats stats, Map<Object, Object> metrics, Map<Object, Object> errors) { int totalAccess = 0; long totalDuration = 0;
for (Map.Entry<Object, Object> entry : metrics.entrySet()) { String key = entry.getKey().toString(); if (key.endsWith(":count")) { totalAccess += Integer.parseInt(entry.getValue().toString()); } else if (key.endsWith(":duration")) { totalDuration += Long.parseLong(entry.getValue().toString()); } }
stats.setTotalAccess(totalAccess); stats.setTotalDuration(totalDuration); stats.setAvgDuration(totalAccess > 0 ? totalDuration / totalAccess : 0);
int totalErrors = 0; for (Object value : errors.values()) { totalErrors += Integer.parseInt(value.toString()); }
stats.setTotalErrors(totalErrors); stats.setErrorRate(totalAccess > 0 ? (double) totalErrors / totalAccess : 0);
stats.setAvailability(totalAccess > 0 ? (double) (totalAccess - totalErrors) / totalAccess : 1.0); }
@Scheduled(fixedDelay = 300000) public void checkTenantPerformanceAnomalies() { try { List<String> activeTenants = getActiveTenants();
for (String tenantId : activeTenants) { TenantPerformanceStats stats = getTenantPerformanceStats(tenantId, LocalDate.now());
if (stats.getErrorRate() > 0.1) { log.warn("租户错误率过高: tenantId={}, errorRate={}", tenantId, stats.getErrorRate()); sendPerformanceAlert(tenantId, "ERROR_RATE_HIGH", stats.getErrorRate()); }
if (stats.getAvgDuration() > 5000) { log.warn("租户响应时间过长: tenantId={}, avgDuration={}", tenantId, stats.getAvgDuration()); sendPerformanceAlert(tenantId, "RESPONSE_TIME_HIGH", stats.getAvgDuration()); }
if (stats.getAvailability() < 0.95) { log.warn("租户可用性过低: tenantId={}, availability={}", tenantId, stats.getAvailability()); sendPerformanceAlert(tenantId, "AVAILABILITY_LOW", stats.getAvailability()); } }
} catch (Exception e) { log.error("检查租户性能异常失败", e); } }
private void sendPerformanceAlert(String tenantId, String alertType, double value) { try { PerformanceAlert alert = new PerformanceAlert(); alert.setTenantId(tenantId); alert.setAlertType(alertType); alert.setValue(value); alert.setTimestamp(LocalDateTime.now());
log.info("发送性能告警: {}", alert);
} catch (Exception e) { log.error("发送性能告警失败: tenantId={}, alertType={}", tenantId, alertType, e); } }
private List<String> getActiveTenants() { return new ArrayList<>(); } }
|