Authored by hugufei

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

package com.yoho.search.common.downgrade.persional;
import java.util.concurrent.atomic.AtomicInteger;
public class KeyCountWithExpiredTime {
private AtomicInteger count;
private long expiredTime;
public KeyCountWithExpiredTime(long expiredTime){
this.count = new AtomicInteger(0);
this.expiredTime = expiredTime;
}
public int incrementAndGet(long newExpiredTime){
//key已过期,过期时间设为newExpiredTime,count设为1
if(this.expiredTime<System.currentTimeMillis()){
this.resetExpiredTime(newExpiredTime);
}else{
this.count.incrementAndGet();
}
return this.count.get();
}
//线程安全
private synchronized void resetExpiredTime(long newExpiredTime) {
if (this.expiredTime < System.currentTimeMillis()) {
this.expiredTime = newExpiredTime;
this.count.set(1);
}
}
}
... ...
... ... @@ -15,45 +15,29 @@ import com.yoho.search.service.base.SearchDynamicConfigService;
@Service
public class PersionalRateLimitService {
private static final Logger DOWNGRADE = LoggerFactory.getLogger("DOWNGRADE");
@Autowired
private SearchRedis searchRedis;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
public boolean isPersionalRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {
return this.isRateLimit(rateLimitName, limitConfig);
}
private Map<String, Long> oldCountMap = new ConcurrentHashMap<String, Long>();
private boolean isRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {
String redisKey = "yohosearch:rateLimit:" + rateLimitName;
try {
long count = searchRedis.searchValueOperations.increment(redisKey, 1).intValue();
if (count == 1) {
searchRedis.searchRedisTemplate.longExpire(redisKey, limitConfig.getSecond(), TimeUnit.SECONDS);
// 如果上一阶段发生降级,则打印日志
Long oldCount = oldCountMap.get(rateLimitName);
if (oldCount != null) {
DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}], redisKey is [{}] ,count is[{}], limitConfig is [{}]", rateLimitName, redisKey, oldCount,limitConfig.toLogInfo());
oldCountMap.remove(rateLimitName);
}
}
if (count > limitConfig.getLimit()) {
oldCountMap.put(rateLimitName, count);
return true;
}
return false;
} catch (Exception e) {
DOWNGRADE.error(e.getMessage(), e);
try {
searchRedis.searchRedisTemplate.delete(redisKey);
} catch (Exception e2) {
DOWNGRADE.error(e2.getMessage(), e2);
}
return false;
}
}
private static final Logger DOWNGRADE = LoggerFactory.getLogger("DOWNGRADE");
private Map<String, KeyCountWithExpiredTime> keyCountMap = new ConcurrentHashMap<String, KeyCountWithExpiredTime>();
private Map<String, Integer> oldCountMap = new ConcurrentHashMap<String, Integer>();
public boolean isPersionalRateLimit(String rateLimitName, PersionalRateLimitConfig limitConfig) {
long expireTime = System.currentTimeMillis() + limitConfig.getSecond() * 1000L;
KeyCountWithExpiredTime keyCountWithExpiredTime = keyCountMap.putIfAbsent(rateLimitName, new KeyCountWithExpiredTime(expireTime));
if (keyCountWithExpiredTime == null) {
keyCountWithExpiredTime = keyCountMap.get(rateLimitName);
}
int currentCount = keyCountWithExpiredTime.incrementAndGet(expireTime);
if (currentCount == 1 && oldCountMap.containsKey(rateLimitName)) {
DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}], oldCount is[{}], limitConfig is [{}]", rateLimitName,oldCountMap.get(rateLimitName), limitConfig.toLogInfo());
oldCountMap.remove(rateLimitName);
}
if (currentCount <= limitConfig.getLimit()) {
return false;
}
oldCountMap.put(rateLimitName, currentCount);
DOWNGRADE.error("PersionalRateLimit happen ,rateLimitName is [{}],currentCount is[{}], limitConfig is [{}]", rateLimitName,currentCount, limitConfig.toLogInfo());
return true;
}
}
... ...