Authored by hugufei

使用内存实现个性化自动降级

  1 +package com.yoho.search.common.downgrade.persional;
  2 +
  3 +import java.util.concurrent.atomic.AtomicInteger;
  4 +
  5 +public class KeyCountWithExpiredTime {
  6 +
  7 + private AtomicInteger count;
  8 + private long expiredTime;
  9 +
  10 + public KeyCountWithExpiredTime(long expiredTime){
  11 + this.count = new AtomicInteger(0);
  12 + this.expiredTime = expiredTime;
  13 + }
  14 +
  15 + public int incrementAndGet(long newExpiredTime){
  16 + //key已过期,过期时间设为newExpiredTime,count设为1
  17 + if(this.expiredTime<System.currentTimeMillis()){
  18 + this.resetExpiredTime(newExpiredTime);
  19 + }else{
  20 + this.count.incrementAndGet();
  21 + }
  22 + return this.count.get();
  23 + }
  24 +
  25 + //线程安全
  26 + private synchronized void resetExpiredTime(long newExpiredTime) {
  27 + if (this.expiredTime < System.currentTimeMillis()) {
  28 + this.expiredTime = newExpiredTime;
  29 + this.count.set(1);
  30 + }
  31 + }
  32 +
  33 +}
@@ -15,45 +15,29 @@ import com.yoho.search.service.base.SearchDynamicConfigService; @@ -15,45 +15,29 @@ import com.yoho.search.service.base.SearchDynamicConfigService;
15 @Service 15 @Service
16 public class PersionalRateLimitService { 16 public class PersionalRateLimitService {
17 17
18 - private static final Logger DOWNGRADE = LoggerFactory.getLogger("DOWNGRADE");  
19 -  
20 - @Autowired  
21 - private SearchRedis searchRedis;  
22 - @Autowired  
23 - private SearchDynamicConfigService searchDynamicConfigService;  
24 -  
25 - public boolean isPersionalRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {  
26 - return this.isRateLimit(rateLimitName, limitConfig);  
27 - }  
28 -  
29 - private Map<String, Long> oldCountMap = new ConcurrentHashMap<String, Long>();  
30 -  
31 - private boolean isRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {  
32 - String redisKey = "yohosearch:rateLimit:" + rateLimitName;  
33 - try {  
34 - long count = searchRedis.searchValueOperations.increment(redisKey, 1).intValue();  
35 - if (count == 1) {  
36 - searchRedis.searchRedisTemplate.longExpire(redisKey, limitConfig.getSecond(), TimeUnit.SECONDS);  
37 - // 如果上一阶段发生降级,则打印日志  
38 - Long oldCount = oldCountMap.get(rateLimitName);  
39 - if (oldCount != null) {  
40 - DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}], redisKey is [{}] ,count is[{}], limitConfig is [{}]", rateLimitName, redisKey, oldCount,limitConfig.toLogInfo());  
41 - oldCountMap.remove(rateLimitName);  
42 - }  
43 - }  
44 - if (count > limitConfig.getLimit()) {  
45 - oldCountMap.put(rateLimitName, count);  
46 - return true;  
47 - }  
48 - return false;  
49 - } catch (Exception e) {  
50 - DOWNGRADE.error(e.getMessage(), e);  
51 - try {  
52 - searchRedis.searchRedisTemplate.delete(redisKey);  
53 - } catch (Exception e2) {  
54 - DOWNGRADE.error(e2.getMessage(), e2);  
55 - }  
56 - return false;  
57 - }  
58 - } 18 + private static final Logger DOWNGRADE = LoggerFactory.getLogger("DOWNGRADE");
  19 +
  20 + private Map<String, KeyCountWithExpiredTime> keyCountMap = new ConcurrentHashMap<String, KeyCountWithExpiredTime>();
  21 +
  22 + private Map<String, Integer> oldCountMap = new ConcurrentHashMap<String, Integer>();
  23 +
  24 + public boolean isPersionalRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {
  25 + long expireTime = System.currentTimeMillis() + limitConfig.getSecond() * 1000L;
  26 + KeyCountWithExpiredTime keyCountWithExpiredTime = keyCountMap.putIfAbsent(rateLimitName, new KeyCountWithExpiredTime(expireTime));
  27 + if (keyCountWithExpiredTime == null) {
  28 + keyCountWithExpiredTime = keyCountMap.get(rateLimitName);
  29 + }
  30 + int currentCount = keyCountWithExpiredTime.incrementAndGet(expireTime);
  31 + if (currentCount == 1 && oldCountMap.containsKey(rateLimitName)) {
  32 + DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}], oldCount is[{}], limitConfig is [{}]", rateLimitName,oldCountMap.get(rateLimitName), limitConfig.toLogInfo());
  33 + oldCountMap.remove(rateLimitName);
  34 + }
  35 + if (currentCount <= limitConfig.getLimit()) {
  36 + return false;
  37 + }
  38 + oldCountMap.put(rateLimitName, currentCount);
  39 + DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}],currentCount is[{}], limitConfig is [{}]", rateLimitName,currentCount, limitConfig.toLogInfo());
  40 + return true;
  41 + }
  42 +
59 } 43 }