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()); }
@Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws CallerException { String reqSV = invoker.getInterface().getName(); String reqMethod = invocation.getMethodName(); Object[] requestParams = invocation.getArguments(); // 交易序列 String tradeSeq = UUIDUtil.genId32(); // 打印请求参数明细 if (CollectionUtil.isEmpty(requestParams)) { LOG.info( "TRADE_SEQ:{},拦截类型:{},请求类(接口):{},请求方法:{},请求参数:{}", tradeSeq, "Dubbo请求参数拦截(无参数)", reqSV, reqMethod, ""); } else { LOG.info( "TRADE_SEQ:{},拦截类型:{},请求类(接口):{},请求方法:{},请求参数:{}", tradeSeq, "Dubbo请求参数拦截(有参数)", reqSV, reqMethod, JSON.toJSONString(requestParams)); } // ThreadLocalUtils.set(REQUEST_PARAM, tradeSeq); // 执行结果 Result result = null; try { // 校验租户ID是否存在 /*boolean isOK=validateTenantId(requestParams); if(!isOK){ throw new BusinessException(MyXAppPaaSConstant.ExceptionCode.PARAM_IS_NULL, "租户ID(tenantId)不能为空!"); }*/ result = invoker.invoke(invocation); if (result.hasException()) { LOG.error( "TRADE_SEQ:{},Dubbo服务端执行{}类中的{}方法发生异常", tradeSeq, reqSV, reqMethod, result.getException()); throw DubboExceptAssembler.assemble(result.getException()); } LOG.info( "TRADE_SEQ:{},拦截类型:{},请求结果:{}", tradeSeq, "Dubbo请求返回结果拦截", JSON.toJSONString(result.getValue())); return result; } catch (Exception ex) { LOG.error("TRADE_SEQ:{},执行{}类中的{}方法发生异常:", tradeSeq, reqSV, reqMethod, ex); RpcResult r = new RpcResult(); r.setException(DubboExceptAssembler.assemble(ex)); return r; } }
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; }
/** * 这里会判断当前调用服务的状态,分析判断是否需要进入降级状态 如果服务在指定的时间区间内累积的错误,达到了配置的次数,则进入服务降级 * 如果满足上面条件,并且满足重试机制,则也不会进入降级流程,而是触发远程服务调用 * * @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 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(); }
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException { String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY); if (ConfigUtils.isNotEmpty(token)) { Class<?> serviceType = invoker.getInterface(); Map<String, String> attachments = inv.getAttachments(); String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY); if (!token.equals(remoteToken)) { throw new RpcException( "Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost()); } } return invoker.invoke(inv); }
/** * 将服务恢复正常 * * @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(); } }
protected RpcException getRpcException( Class<?> type, URL url, Invocation invocation, Throwable e) { RpcException re = new RpcException( "Failed to invoke remote service: " + type + ", method: " + invocation.getMethodName() + ", cause: " + e.getMessage(), e); re.setCode(getErrorCode(e)); return re; }
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 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; } }
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String generic = invoker.getUrl().getParameter(Constants.GENERIC_KEY); if (ProtocolUtils.isGeneric(generic) && !Constants.$INVOKE.equals(invocation.getMethodName()) && invocation instanceof RpcInvocation) { RpcInvocation invocation2 = (RpcInvocation) invocation; String methodName = invocation2.getMethodName(); Class<?>[] parameterTypes = invocation2.getParameterTypes(); Object[] arguments = invocation2.getArguments(); String[] types = new String[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { types[i] = ReflectUtils.getName(parameterTypes[i]); } Object[] args = PojoUtils.generalize(arguments); invocation2.setMethodName(Constants.$INVOKE); invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES); invocation2.setArguments(new Object[] {methodName, types, args}); Result result = invoker.invoke(invocation2); if (!result.hasException()) { Object value = result.getValue(); try { Method method = invoker.getInterface().getMethod(methodName, parameterTypes); return new RpcResult( PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType())); } catch (NoSuchMethodException e) { throw new RpcException(e.getMessage(), e); } } else if (result.getException() instanceof GenericException) { GenericException exception = (GenericException) result.getException(); try { String className = exception.getExceptionClass(); Class<?> clazz = ReflectUtils.forName(className); Throwable targetException = null; Throwable lastException = null; try { targetException = (Throwable) clazz.newInstance(); } catch (Throwable e) { lastException = e; for (Constructor<?> constructor : clazz.getConstructors()) { try { targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]); break; } catch (Throwable e1) { lastException = e1; } } } if (targetException != null) { try { Field field = Throwable.class.getDeclaredField("detailMessage"); if (!field.isAccessible()) { field.setAccessible(true); } field.set(targetException, exception.getExceptionMessage()); } catch (Throwable e) { logger.warn(e.getMessage(), e); } result = new RpcResult(targetException); } else if (lastException != null) { throw lastException; } } catch (Throwable e) { throw new RpcException( "Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e); } } return result; } if (invocation.getMethodName().equals(Constants.$INVOKE) && invocation.getArguments() != null && invocation.getArguments().length == 3 && ProtocolUtils.isGeneric(generic)) { if (ProtocolUtils.isJavaGenericSerialization(generic)) { Object[] args = (Object[]) invocation.getArguments()[2]; for (Object arg : args) { if (!(byte[].class == arg.getClass())) { error(arg.getClass().getName()); } } } ((RpcInvocation) invocation) .setAttachment( Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY)); } return invoker.invoke(invocation); }