/** * 这里会判断当前调用服务的状态,分析判断是否需要进入降级状态 如果服务在指定的时间区间内累积的错误,达到了配置的次数,则进入服务降级 * 如果满足上面条件,并且满足重试机制,则也不会进入降级流程,而是触发远程服务调用 * * @param invoker * @param invocation * @return */ private boolean checkNeedCircuitBreak(Invoker<?> invoker, Invocation invocation) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); String methodKey = Config.getMethodPropertyName(invoker, invocation).toString(); int limit = Config.getBreakLimit(invoker, invocation); BreakCounter breakCounter = breakCounterMap.get(methodKey); if (breakCounter != null && breakCounter.isEnable()) { long currentExceptionCount = breakCounter.getCurrentExceptionCount(); long currentBreakCount = breakCounter.getCurrentBreakCount(); logger.info( "[{}] check invoke [{}.{}] circuit break,current exception count [{}] limit [{}]", localHost, interfaceName, method, currentExceptionCount, limit); if (limit <= currentExceptionCount) { if (currentBreakCount > 0 && needRetry(invoker, invocation, currentBreakCount)) { logger.info( "[{}] retry invoke [{}.{}] current break count [{}]", localHost, interfaceName, method, currentBreakCount); breakCounter.incrementRetryTimes(); return false; } return true; } } return false; }
private void caughtException(Invoker<?> invoker, Invocation invocation, Exception e) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); StringBuffer interfaceConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX); interfaceConfig.append(interfaceName); StringBuffer methodConfig = new StringBuffer(interfaceConfig.toString()); methodConfig.append(".").append(method); String methodKey = methodConfig.toString(); int timeout = invoker .getUrl() .getMethodParameter( invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); int limit = Config.getBreakLimit(invoker, invocation); // 一个异常的有效期,是通过连续出现异常数量乘以每个调用的超时时间,比如你配置连续出现10次异常之后进行服务降级,并且每次服务调用的超时时间是2000ms的话,同时 // 每个服务重试次数是为2次,那么就是在(2+1)*2000*10 ExceptionMarker breakMarker = new ExceptionMarker(System.currentTimeMillis(), limit * timeout, e); if (!breakCounterMap.containsKey(methodKey)) { BreakCounter oldValue = breakCounterMap.putIfAbsent(methodKey, new BreakCounter(methodKey)); // 返回的oldValue为空,表示之前没有创建了赌赢的异常计数器,则需要对它分配一个loop if (oldValue == null) { nextLoop().register(breakCounterMap.get(methodKey)); } } BreakCounter counter = breakCounterMap.get(methodKey); counter.addExceptionMarker(breakMarker); logger.info( "[{}] caught exception for rpc invoke [{}.{}],current exception count [{}]", localHost, interfaceName, method, counter.getCurrentExceptionCount()); }
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if (Config.checkFunctionSwitch(invoker, invocation)) { logger.info("[{}] had [{}] breaker", localHost, breakCounterMap.size()); return wrapBreakerInvoke(invoker, invocation); } Result result = invoker.invoke(invocation); toBeNormal(invoker, invocation); return result; }
private boolean needRetry(Invoker<?> invoker, Invocation invocation, long currentBreakCount) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); int frequency = Config.getRetryFrequency(invoker, invocation); logger.info( "[{}] check invoke [{}.{}] need retry,current break count [{}],retry frequency [{}]", localHost, interfaceName, method, currentBreakCount, frequency); if (currentBreakCount % frequency == 0) { logger.info("[{}] retry invoke [{}.{}]", localHost, interfaceName, method); return true; } return false; }
/** * Created by bieber on 2015/4/30. Dubbo服务降级Filter 通过拦截每个方法的请求,并且读取每个方法对服务降级条件的配置 从而自动进行服务降级,以及服务恢复 */ @Activate(group = {Constants.CONSUMER}) public class RemoteFacadeCircuitBreaker implements Filter { private static final Logger logger = LoggerFactory.getLogger("CIRCUITBREAKER"); private static final InetAddress localHost = Config.getLocalAddress(); // 用于存储某个方法出现异常的计数器key:interfaceName.methodName,value:对应的异常计数器 private volatile ConcurrentHashMap<String, BreakCounter> breakCounterMap = new ConcurrentHashMap<String, BreakCounter>(); // 对某个方法异常计数器处理器,用于分析记录的异常到当前实现是否失效了(为了满足在某个时间内出现异常次数),如果失效将从BreakCounter中移除 private BreakCounterLoop[] breakCounterLoops = new BreakCounterLoop[Runtime.getRuntime().availableProcessors()]; // 获取dubbo的代理工程扩展 private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); // 缓存服务降级代理类的Invoker,避免重复创建 private static final ConcurrentHashMap<String, Invoker> CIRCUIT_BREAKER_INVOKER_CACHE = new ConcurrentHashMap<String, Invoker>(); private volatile AtomicLong loopCount = new AtomicLong(0); public RemoteFacadeCircuitBreaker() { String intervalConf = ConfigUtils.getProperty("dubbo.reference.check.break.marker.interval", "60000"); logger.info( "[{}] has already been initialized circuit breaker,check break marker interval [{}]", localHost, intervalConf); long interval = Long.parseLong(intervalConf); for (int i = 0; i < breakCounterLoops.length; i++) { BreakCounterLoop loop = new BreakCounterLoop(interval); breakCounterLoops[i] = loop; } } // 获取下一个遍历器 private BreakCounterLoop nextLoop() { return breakCounterLoops[((int) (loopCount.incrementAndGet() % breakCounterLoops.length))]; } public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { if (Config.checkFunctionSwitch(invoker, invocation)) { logger.info("[{}] had [{}] breaker", localHost, breakCounterMap.size()); return wrapBreakerInvoke(invoker, invocation); } Result result = invoker.invoke(invocation); toBeNormal(invoker, invocation); return result; } private Result wrapBreakerInvoke(Invoker<?> invoker, Invocation invocation) throws RpcException { // 首先检查是否需要进入服务降级流程 if (checkNeedCircuitBreak(invoker, invocation)) { logger.info( "[{}] activate the circuit break for url [{}],invoke method [{}]", localHost, invoker.getUrl(), invocation.getMethodName()); // 进入服务降级 return doCircuitBreak(invoker, invocation); } try { Result result = invoker.invoke(invocation); // 将该服务从服务降级中恢复出来 toBeNormal(invoker, invocation); return result; } catch (RpcException e) { // 如果是请求超时或者网络异常,进行异常统计 if (!e.isBiz()) { caughtException(invoker, invocation, e); } throw e; } } /** * 将服务恢复正常 * * @param invoker * @param invocation */ private void toBeNormal(Invoker<?> invoker, Invocation invocation) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); StringBuffer methodConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX); methodConfig.append(interfaceName).append(".").append(method); String methodKey = methodConfig.toString(); // 从其中删除对应的异常计数器 BreakCounter counter = breakCounterMap.remove(methodKey); if (counter != null) { logger.info("[{}] [{}.{}] to be normal", localHost, interfaceName, methodKey); // 将这个counter设置为失效 counter.disable(); } } /** * 这里会判断当前调用服务的状态,分析判断是否需要进入降级状态 如果服务在指定的时间区间内累积的错误,达到了配置的次数,则进入服务降级 * 如果满足上面条件,并且满足重试机制,则也不会进入降级流程,而是触发远程服务调用 * * @param invoker * @param invocation * @return */ private boolean checkNeedCircuitBreak(Invoker<?> invoker, Invocation invocation) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); String methodKey = Config.getMethodPropertyName(invoker, invocation).toString(); int limit = Config.getBreakLimit(invoker, invocation); BreakCounter breakCounter = breakCounterMap.get(methodKey); if (breakCounter != null && breakCounter.isEnable()) { long currentExceptionCount = breakCounter.getCurrentExceptionCount(); long currentBreakCount = breakCounter.getCurrentBreakCount(); logger.info( "[{}] check invoke [{}.{}] circuit break,current exception count [{}] limit [{}]", localHost, interfaceName, method, currentExceptionCount, limit); if (limit <= currentExceptionCount) { if (currentBreakCount > 0 && needRetry(invoker, invocation, currentBreakCount)) { logger.info( "[{}] retry invoke [{}.{}] current break count [{}]", localHost, interfaceName, method, currentBreakCount); breakCounter.incrementRetryTimes(); return false; } return true; } } return false; } private boolean needRetry(Invoker<?> invoker, Invocation invocation, long currentBreakCount) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); int frequency = Config.getRetryFrequency(invoker, invocation); logger.info( "[{}] check invoke [{}.{}] need retry,current break count [{}],retry frequency [{}]", localHost, interfaceName, method, currentBreakCount, frequency); if (currentBreakCount % frequency == 0) { logger.info("[{}] retry invoke [{}.{}]", localHost, interfaceName, method); return true; } return false; } private <T extends Object> Result doCircuitBreak(Invoker<?> invoker, Invocation invocation) throws RpcException { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String circuitBreaker = interfaceName + "CircuitBreak"; incrementBreakCount(invoker, invocation); try { logger.info("[{}] check has class [{}] to handle circuit break", localHost, circuitBreaker); Invoker<?> breakerInvoker = null; if (CIRCUIT_BREAKER_INVOKER_CACHE.containsKey(circuitBreaker)) { breakerInvoker = CIRCUIT_BREAKER_INVOKER_CACHE.get(circuitBreaker); } else { Class<T> breakerType = (Class<T>) Class.forName(circuitBreaker); Class<T> interfaceType = (Class<T>) Class.forName(interfaceName); if (interfaceType.isAssignableFrom(breakerType)) { logger.info("[{}] handle circuit break by class [{}]", localHost, circuitBreaker); T breaker = breakerType.newInstance(); breakerInvoker = proxyFactory.getInvoker(breaker, interfaceType, invoker.getUrl()); Invoker<?> oldInvoker = CIRCUIT_BREAKER_INVOKER_CACHE.putIfAbsent(circuitBreaker, breakerInvoker); if (oldInvoker != null) { breakerInvoker = oldInvoker; } } } if (breakerInvoker != null) { return breakerInvoker.invoke(invocation); } } catch (Exception e) { logger.error("failed to invoke circuit breaker", e); } logger.info("[{}] handle circuit break by exception", localHost); CircuitBreakerException baseBusinessException = new CircuitBreakerException(interfaceName, invocation.getMethodName()); throw baseBusinessException; } private void incrementBreakCount(Invoker<?> invoker, Invocation invocation) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); StringBuffer interfaceConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX); interfaceConfig.append(interfaceName); StringBuffer methodConfig = new StringBuffer(interfaceConfig.toString()); methodConfig.append(".").append(method); String methodKey = methodConfig.toString(); BreakCounter counter = breakCounterMap.get(methodKey); counter.incrementBreakCount(); } private void caughtException(Invoker<?> invoker, Invocation invocation, Exception e) { String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY); String method = invocation.getMethodName(); StringBuffer interfaceConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX); interfaceConfig.append(interfaceName); StringBuffer methodConfig = new StringBuffer(interfaceConfig.toString()); methodConfig.append(".").append(method); String methodKey = methodConfig.toString(); int timeout = invoker .getUrl() .getMethodParameter( invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); int limit = Config.getBreakLimit(invoker, invocation); // 一个异常的有效期,是通过连续出现异常数量乘以每个调用的超时时间,比如你配置连续出现10次异常之后进行服务降级,并且每次服务调用的超时时间是2000ms的话,同时 // 每个服务重试次数是为2次,那么就是在(2+1)*2000*10 ExceptionMarker breakMarker = new ExceptionMarker(System.currentTimeMillis(), limit * timeout, e); if (!breakCounterMap.containsKey(methodKey)) { BreakCounter oldValue = breakCounterMap.putIfAbsent(methodKey, new BreakCounter(methodKey)); // 返回的oldValue为空,表示之前没有创建了赌赢的异常计数器,则需要对它分配一个loop if (oldValue == null) { nextLoop().register(breakCounterMap.get(methodKey)); } } BreakCounter counter = breakCounterMap.get(methodKey); counter.addExceptionMarker(breakMarker); logger.info( "[{}] caught exception for rpc invoke [{}.{}],current exception count [{}]", localHost, interfaceName, method, counter.getCurrentExceptionCount()); } }