微服务调用之重试和负载均衡

Retry机制

微服务架构中,需要频繁调用各个service进行业务逻辑交互,如果调用失败,如何处理,如何重试?spring cloud提供了retry机制。

 @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public boolean collideThridWhiteList(User user, String callTag, String whiteListType) throws  ServiceException {
        boolean isWhiteList = false;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("callTag", "goose_card");
        paramMap.put("userId", user.getThirdUserId());
        paramMap.put("whiteListType", "br");
        HttpEntity request = new HttpEntity(paramMap, headers);
        LOGGER.info("collideThridWhiteList:url:{}", thirdWhitelistUrl);
        String result = restTemplate.postForObject(thirdWhitelistUrl, request, String.class);//可能失败的rest调用
        LOGGER.info("collideThridWhiteList:res:{}", result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject!=null&&jsonObject.get("code").toString().equals("-1")){
            throw  new ServiceException("service is available");
        }
        JSONObject jsonObjectBean = jsonObject.getJSONObject("bean");
        UserHitWhiteLog userHitWhiteLog = new UserHitWhiteLog();
        userHitWhiteLog.setCreateTime(new Date());
        userHitWhiteLog.setUpdateTime(new Date());
        userHitWhiteLog.setUserId(user.getId());
        userHitWhiteLog.setRequestParam(JSONObject.toJSONString(paramMap));
        userHitWhiteLog.setResultDesc(jsonObject.toJSONString());
        if (jsonObjectBean != null) {
            Object jsonObjectResult = jsonObjectBean.get("inWhiteList");
            if (jsonObjectResult != null) {
                userHitWhiteLog.setHitState(1);
                isWhiteList = true;
            }
        } else {
            userHitWhiteLog.setHitState(0);
        }
        userHitWhiteLogMapper.insert(userHitWhiteLog);
        return isWhiteList;
    }
}

如果上面的rest调用失败,如果进行retry,我们一起来尝试一下。

1 在启动类enable retry

@SpringBootApplication
@ComponentScan(value = { "com.puhui" })
@EnableAsync
@EnableRetry
public class BootApplication implements DisposableBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(BootApplication.class);

    private static ConfigurableApplicationContext ctx;

    public static void main(String[] args) {
        ctx = SpringApplication.run(BootApplication.class, args);

        LOGGER.info("spring.profiles.active:");
        for (String str : ctx.getEnvironment().getActiveProfiles()) {
            LOGGER.info(str);
        }
        LOGGER.info("Boot Server started.");
        System.setProperty("java.net.preferIPv4Stack", "true");
    }

    @Override
    public void destroy() throws Exception {
        if (null != ctx && ctx.isRunning()) {
            ctx.close();
        }
    }

2 在需要retry的方法增加retry声明。

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    @Retryable(value ={ServiceException.class},maxAttempts = 3,backoff = @Backoff(delay = 2l,multiplier = 1))
    public boolean collideThridWhiteList(User user, String callTag, String whiteListType) throws  ServiceException {
        boolean isWhiteList = false;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("callTag", "goose_card");
        paramMap.put("userId", user.getThirdUserId());
        paramMap.put("whiteListType", "br");
        HttpEntity request = new HttpEntity(paramMap, headers);
        LOGGER.info("collideThridWhiteList:url:{}", thirdWhitelistUrl);
        String result = restTemplate.postForObject(thirdWhitelistUrl, request, String.class);
        LOGGER.info("collideThridWhiteList:res:{}", result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject!=null&&jsonObject.get("code").toString().equals("-1")){
            throw  new ServiceException("service is unavailable");
        }
        JSONObject jsonObjectBean = jsonObject.getJSONObject("bean");
        UserHitWhiteLog userHitWhiteLog = new UserHitWhiteLog();
        userHitWhiteLog.setCreateTime(new Date());
        userHitWhiteLog.setUpdateTime(new Date());
        userHitWhiteLog.setUserId(user.getId());
        userHitWhiteLog.setRequestParam(JSONObject.toJSONString(paramMap));
        userHitWhiteLog.setResultDesc(jsonObject.toJSONString());
        if (jsonObjectBean != null) {
            Object jsonObjectResult = jsonObjectBean.get("inWhiteList");
            if (jsonObjectResult != null) {
                userHitWhiteLog.setHitState(1);
                isWhiteList = true;
            }
        } else {
            userHitWhiteLog.setHitState(0);
        }
        userHitWhiteLogMapper.insert(userHitWhiteLog);
        return isWhiteList;
    }

3 测试

我们制造个service exception,测试重试机制是否生效,修改if条件,抛出service exception

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
@Retryable(value ={ServiceException.class},maxAttempts = 3,backoff = @Backoff(delay = 2l,multiplier = 1))
public boolean collideThridWhiteList(User user, String callTag, String whiteListType) throws  ServiceException {
    boolean isWhiteList = false;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("callTag", "goose_card");
    paramMap.put("userId", user.getThirdUserId());
    paramMap.put("whiteListType", "br");
    HttpEntity request = new HttpEntity(paramMap, headers);
    LOGGER.info("collideThridWhiteList:url:{}", thirdWhitelistUrl);
    String result = restTemplate.postForObject(thirdWhitelistUrl, request, String.class);
    LOGGER.info("collideThridWhiteList:res:{}", result);
    JSONObject jsonObject = JSONObject.parseObject(result);
    if (jsonObject!=null&&jsonObject.get("code").toString().equals("0")){
        throw  new ServiceException("service is unavailable");
    }
    JSONObject jsonObjectBean = jsonObject.getJSONObject("bean");
    UserHitWhiteLog userHitWhiteLog = new UserHitWhiteLog();
    userHitWhiteLog.setCreateTime(new Date());
    userHitWhiteLog.setUpdateTime(new Date());
    userHitWhiteLog.setUserId(user.getId());
    userHitWhiteLog.setRequestParam(JSONObject.toJSONString(paramMap));
    userHitWhiteLog.setResultDesc(jsonObject.toJSONString());
    if (jsonObjectBean != null) {
        Object jsonObjectResult = jsonObjectBean.get("inWhiteList");
        if (jsonObjectResult != null) {
            userHitWhiteLog.setHitState(1);
            isWhiteList = true;
        }
    } else {
        userHitWhiteLog.setHitState(0);
    }
    userHitWhiteLogMapper.insert(userHitWhiteLog);
    return isWhiteList;
}
2018-05-24 15:57:21.408  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:url:http://qianzhan-core-api.qianzhancore.test/api/v1/getWhiteList
2018-05-24 15:57:25.006  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:res:{"code":0,"msgCode":"0000","message":"操作成功","bean":{"inWhiteList":true}}
2018-05-24 15:57:34.681  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:url:http://qianzhan-core-api.qianzhancore.test/api/v1/getWhiteList
2018-05-24 15:57:34.860  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:res:{"code":0,"msgCode":"0000","message":"操作成功","bean":{"inWhiteList":true}}
2018-05-24 15:57:36.433  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:url:http://qianzhan-core-api.qianzhancore.test/api/v1/getWhiteList
2018-05-24 15:57:36.575  INFO 56872 --- [nio-8080-exec-1] c.p.g.w.s.impl.IdNoValidServiceImpl      : collideThridWhiteList:res:{"code":0,"msgCode":"0000","message":"操作成功","bean":{"inWhiteList":true}}
2018-05-24 15:57:36.580 ERROR 56872 --- [nio-8080-exec-1] c.p.g.web.controller.UserController      : failed to check white list {}


com.puhui.goosecard.common.exception.ServiceException: service is unavailable
at com.puhui.goosecard.web.service.impl.IdNoValidServiceImpl.collideThridWhiteList(IdNoValidServiceImpl.java:248)
at com.puhui.goosecard.web.service.impl.IdNoValidServiceImpl$$FastClassBySpringCGLIB$$3df4f807.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:263)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:154)
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:101)
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
at com.puhui.goosecard.web.service.impl.IdNoValidServiceImpl$$EnhancerBySpringCGLIB$$9deab204.collideThridWhiteList(<generated>)
at com.puhui.goosecard.web.controller.IdNoController.idNoValid(IdNoController.java:168)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at com.puhui.goosecard.web.filter.RightFilter.doFilter(RightFilter.java:70)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:208)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)

从上面结果可以看出,重试3次后,仍然失败,抛出异常。间隔配置为5s,我们没有利用@recovery进行异常的处理,有兴趣的同学可以自己试试。





猜你喜欢

转载自blog.csdn.net/hanruikai/article/details/80435184