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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
| @Service @Slf4j public class AccountMonitoringService {
@Autowired private MeterRegistry meterRegistry;
@Autowired private RedisTemplate<String, Object> redisTemplate;
public void recordAccountOperation(String accountNo, String operation, long duration) { try { Counter.builder("account.operation.count") .tag("account_no", accountNo) .tag("operation", operation) .register(meterRegistry) .increment();
Timer.builder("account.operation.duration") .tag("account_no", accountNo) .tag("operation", operation) .register(meterRegistry) .record(duration, TimeUnit.MILLISECONDS);
String key = "account:metrics:" + accountNo + ":" + 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("记录账户操作指标失败: accountNo={}, operation={}", accountNo, operation, e); } }
public void recordAccountBalance(String accountNo, BigDecimal balance) { try { Gauge.builder("account.balance") .tag("account_no", accountNo) .register(meterRegistry, balance, BigDecimal::doubleValue);
String key = "account:balance:" + accountNo; redisTemplate.opsForValue().set(key, balance, Duration.ofHours(1));
} catch (Exception e) { log.error("记录账户余额指标失败: accountNo={}", accountNo, e); } }
@Scheduled(fixedDelay = 300000) public void checkAccountAnomalies() { try { List<Account> accounts = accountMapper.selectAll();
for (Account account : accounts) { checkBalanceAnomaly(account);
checkTransactionAnomaly(account);
checkRiskAnomaly(account); }
} catch (Exception e) { log.error("检查账户异常失败", e); } }
private void checkBalanceAnomaly(Account account) { if (account.getBalance().compareTo(BigDecimal.ZERO) < 0) { log.warn("账户余额为负数: accountNo={}, balance={}", account.getAccountNo(), account.getBalance()); sendBalanceAlert(account, "NEGATIVE_BALANCE", account.getBalance()); }
BigDecimal previousBalance = getPreviousBalance(account.getAccountNo()); if (previousBalance != null) { BigDecimal growth = account.getBalance().subtract(previousBalance); if (growth.compareTo(new BigDecimal("100000")) > 0) { log.warn("账户余额异常增长: accountNo={}, growth={}", account.getAccountNo(), growth); sendBalanceAlert(account, "ABNORMAL_GROWTH", growth); } } }
private void checkTransactionAnomaly(Account account) { int hourlyCount = getHourlyTransactionCount(account.getAccountNo()); if (hourlyCount > 50) { log.warn("账户交易频率过高: accountNo={}, count={}", account.getAccountNo(), hourlyCount); sendTransactionAlert(account, "HIGH_FREQUENCY", hourlyCount); }
BigDecimal maxAmount = getMaxTransactionAmount(account.getAccountNo()); if (maxAmount.compareTo(new BigDecimal("50000")) > 0) { log.warn("账户存在大额交易: accountNo={}, amount={}", account.getAccountNo(), maxAmount); sendTransactionAlert(account, "LARGE_AMOUNT", maxAmount); } }
private void checkRiskAnomaly(Account account) { if (account.getRiskLevel() == RiskLevel.HIGH) { log.warn("账户风险等级高: accountNo={}", account.getAccountNo()); sendRiskAlert(account, "HIGH_RISK", account.getRiskLevel()); }
int consecutiveFailures = getConsecutiveFailures(account.getAccountNo()); if (consecutiveFailures > 10) { log.warn("账户连续失败次数过多: accountNo={}, failures={}", account.getAccountNo(), consecutiveFailures); sendRiskAlert(account, "CONSECUTIVE_FAILURES", consecutiveFailures); } }
private void sendBalanceAlert(Account account, String alertType, BigDecimal value) { try { BalanceAlert alert = new BalanceAlert(); alert.setAccountNo(account.getAccountNo()); alert.setAlertType(alertType); alert.setValue(value); alert.setTimestamp(LocalDateTime.now());
log.info("发送余额告警: {}", alert);
} catch (Exception e) { log.error("发送余额告警失败: accountNo={}, alertType={}", account.getAccountNo(), alertType, e); } }
private void sendTransactionAlert(Account account, String alertType, Object value) { try { TransactionAlert alert = new TransactionAlert(); alert.setAccountNo(account.getAccountNo()); alert.setAlertType(alertType); alert.setValue(value); alert.setTimestamp(LocalDateTime.now());
log.info("发送交易告警: {}", alert);
} catch (Exception e) { log.error("发送交易告警失败: accountNo={}, alertType={}", account.getAccountNo(), alertType, e); } }
private void sendRiskAlert(Account account, String alertType, Object value) { try { RiskAlert alert = new RiskAlert(); alert.setAccountNo(account.getAccountNo()); alert.setAlertType(alertType); alert.setValue(value); alert.setTimestamp(LocalDateTime.now());
log.info("发送风险告警: {}", alert);
} catch (Exception e) { log.error("发送风险告警失败: accountNo={}, alertType={}", account.getAccountNo(), alertType, e); } }
private BigDecimal getPreviousBalance(String accountNo) { String key = "account:balance:" + accountNo; Object balance = redisTemplate.opsForValue().get(key); return balance != null ? (BigDecimal) balance : null; }
private int getHourlyTransactionCount(String accountNo) { String key = "account:hourly:count:" + accountNo + ":" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHH")); Object count = redisTemplate.opsForValue().get(key); return count != null ? (Integer) count : 0; }
private BigDecimal getMaxTransactionAmount(String accountNo) { String key = "account:max:amount:" + accountNo + ":" + LocalDate.now().toString(); Object amount = redisTemplate.opsForValue().get(key); return amount != null ? (BigDecimal) amount : BigDecimal.ZERO; }
private int getConsecutiveFailures(String accountNo) { String key = "account:failures:" + accountNo; Object count = redisTemplate.opsForValue().get(key); return count != null ? (Integer) count : 0; } }
|