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
|
@Service @Slf4j public class ResilientRiskControlService { @Autowired private PaymentRiskRepository riskRepository; @Autowired private RedisTemplate<String, Object> redisTemplate; private final CircuitBreaker circuitBreaker; private final RateLimiter rateLimiter; public ResilientRiskControlService() { this.circuitBreaker = CircuitBreaker.ofDefaults("riskControl"); circuitBreaker.getEventPublisher() .onStateTransition(event -> log.info("熔断器状态变化: {} -> {}", event.getStateTransition().getFromState(), event.getStateTransition().getToState())); this.rateLimiter = RateLimiter.create(100); }
public RiskCheckResult checkPaymentRisk(PaymentRequest request) { if (!rateLimiter.tryAcquire(Duration.ofMillis(100))) { log.warn("风控服务限流触发,用户: {}", request.getUserId()); return RiskCheckResult.defaultLowRisk(); } return circuitBreaker.executeSupplier(() -> { return performRiskCheckWithCache(request); }); } private RiskCheckResult performRiskCheckWithCache(PaymentRequest request) { String cacheKey = "risk_check:" + request.getUserId(); RiskCheckResult cached = getCachedResult(cacheKey); if (cached != null) { log.debug("命中风控缓存,用户: {}", request.getUserId()); return cached; } RiskCheckResult result = performOptimizedRiskCheck(request); cacheResult(cacheKey, result, Duration.ofMinutes(5)); return result; } private RiskCheckResult performOptimizedRiskCheck(PaymentRequest request) { try { List<PaymentRecord> recentPayments = riskRepository .findRecentPaymentsByUserOptimized( request.getUserId(), LocalDateTime.now().minusDays(7), PageRequest.of(0, 100) ); return performSimplifiedRiskAnalysis(recentPayments, request); } catch (Exception e) { log.error("风控查询异常,用户: {}, 错误: {}", request.getUserId(), e.getMessage()); return RiskCheckResult.defaultMediumRisk(); } } private RiskCheckResult getCachedResult(String cacheKey) { try { return (RiskCheckResult) redisTemplate.opsForValue().get(cacheKey); } catch (Exception e) { log.warn("获取缓存失败: {}", e.getMessage()); return null; } } private void cacheResult(String cacheKey, RiskCheckResult result, Duration ttl) { try { redisTemplate.opsForValue().set(cacheKey, result, ttl); } catch (Exception e) { log.warn("设置缓存失败: {}", e.getMessage()); } } private RiskCheckResult performSimplifiedRiskAnalysis(List<PaymentRecord> records, PaymentRequest request) { long totalAmount = records.stream() .mapToLong(PaymentRecord::getAmount) .sum(); int riskScore = calculateRiskScore(totalAmount, records.size(), request.getAmount()); return new RiskCheckResult(riskScore, riskScore > 80 ? "HIGH" : "LOW"); } private int calculateRiskScore(long totalAmount, int transactionCount, long currentAmount) { int score = 0; if (totalAmount > 100000) score += 30; if (transactionCount > 50) score += 20; if (currentAmount > 10000) score += 25; return Math.min(score, 100); } }
@Repository public interface PaymentRiskRepository extends JpaRepository<PaymentRecord, Long> { @Query(value = "SELECT p FROM PaymentRecord p WHERE p.userId = :userId " + "AND p.createdTime >= :startTime ORDER BY p.createdTime DESC") @QueryHints(@QueryHint(name = "javax.persistence.query.timeout", value = "2000")) List<PaymentRecord> findRecentPaymentsByUserOptimized(@Param("userId") Long userId, @Param("startTime") LocalDateTime startTime, Pageable pageable); }
|