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();
 }
Exemplo n.º 6
0
 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();
   }
 }
Exemplo n.º 8
0
 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;
   }
 }
Exemplo n.º 11
0
  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);
  }