Ribbon单独使用,配置自动重试,实现负载均衡和高可用方式

 更新时间:2022年12月28日 14:33:16   作者:DayDayUp丶  
这篇文章主要介绍了Ribbon单独使用,配置自动重试,实现负载均衡和高可用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

一、前言

1.1 实现目标

服务A调用服务B1和B2(B1和B2提供同种服务),当服务B1/B2在停止和重新发布阶段,或B1/B2有一个服务故障时,

  • 需保证服务A正常调用B服务,达到无感知发布的效果(服务B高可用)
  • 需保证服务A的请求负载均衡,避免某个B服务节点压力过大(服务B负载均衡)

说明:这里是独立使用Ribbon,不依赖于Eureka、Zookeeper等任何服务注册发现组件。

1.2 环境

JDK 1.8,SpringCloud Greenwich.SR2,SpringBoot 2.1.3.RELEASE

二、实现

本文示例,CONSUMER-SERVICE服务调用PRODUCER-SERVICE服务。在进行以下步骤前,请先启动两个普通的SpringBoot服务PRODUCER-SERVICE。

2.1 pom依赖

因为这里独立使用Ribbon,所以CONSUMER-SERVICE只需要spring-cloud-starter-netflix-ribbon,启动主类也无需更多的注解,如

@EnableEurekaClient、@EnableDiscoveryClient、@EnableCircuitBreaker等,只需保留@SpringBootApplication即可。

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.2 RestTemplate配置

Ribbon是对RestTemplate的加强,需要为RestTemplate添加注解@LoadBalanced,使之具有负载均衡能力。如下:

@Bean
@LoadBalanced
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
    RestTemplate restTemplate = new RestTemplate(factory);
    restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    return restTemplate;
}

2.3 Ribbon配置

注意:网上和书上很多教程都没有提到ribbon.restclient.enabled这一配置,导致再怎么尝试都无法成功自动重试。

spring.application.name=CONSUMER-SERVICE
server.port=8801
 
ribbon.restclient.enabled=true
#开启重试机制
spring.cloud.loadbalancer.retry.enabled=true
#请求连接的超时时间
PRODUCER-SERVICE.ribbon.ConnectTimeout=250
#请求处理的超时时间
PRODUCER-SERVICE.ribbon.ReadTimeout=1000
#对所有操作请求都进行重试,默认false,只有GET请求会重试;这是防止POST等对数据有影响的请求在重试后因为接口未做幂等性导致数据异常,影响较大
PRODUCER-SERVICE.ribbon.OkToRetryOnAllOperations=true
#指定请求重试开关,经调试源码该属性未被使用,疑似bug,导致不论怎么设置,都是只有服务提供者的Get请求可以被自动重试
#PRODUCER-SERVICE.ribbon.RequestSpecificRetryOn=true
#切换实例的重试次数
PRODUCER-SERVICE.ribbon.MaxAutoRetriesNextServer=2
#对当前实例的重试次数
PRODUCER-SERVICE.ribbon.MaxAutoRetries=1
 
#服务PRODUCER-SERVICE的地址
PRODUCER-SERVICE.ribbon.listOfServers=localhost:8080,localhost:8083

2.4 Ribbon调用服务

在Controller中,注入RestTemplate,使用服务名(即spring.application.name)的方式,调用PRODUCER-SERVICE服务的GET接口,如下:

@Controller
@RequestMapping("consumer/api")
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;
 
    @GetMapping("/test")
    @ResponseBody
    public String test() {
        ResponseEntity<String> entity = restTemplate
                .getForEntity("http://PRODUCER-SERVICE/outer/data?res=3&msgKey=token123", String.class);
        return entity.getBody();
    }
}

三、测试运行

3.1 负载均衡测试

启动一个消费者服务CONSUMER-SERVICE,多次访问/consumer/api/test,可以通过给PRODECER-SERVICE服务的/outer/data接口添加调试日志的打印,来确认默认使用了轮询的负载均衡策略。

3.2 高可用测试

停止其中一个PRODECER-SERVICE服务实例,确认轮询到已停止的服务时,可以成功地在未停止的服务上自动重试请求。

四、无法成功自动重试的几种情况

本人在单独使用Ribbon的过程中,碰到以下几种无法自动重试其他服务节点的情况:

4.1 ribbon.restclient.enabled

遇到Ribbon的问题,网上一搜,千篇一律,也不知道作者们是否亲自实践证明可用,就随意发篇文章。言归正传,若不设置ribbon.restclient.enabled=true,在本人的实验环境中是无法自动重试的。

4.2 Maven打包有警告

在SpringCloud生态的开发中,各组件往往自动依赖了很多其他的jar包,如果向Maven本地仓库下载的过程中,网络不好,就会下载到一份不完整的jar包或pom文件,最终可能会导致打包出错。下面是在使用Maven打包项目时,比较常见下面的警告:

[WARNING] The POM for com.sun.jersey:jersey-core:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available
[WARNING] The POM for com.sun.jersey:jersey-client:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available
...

可以看出来,提示我们传递依赖将失效,所以有可能整个打包过程是SUCCESS的,但是最后启动jar包时,却可能报NoClassDef等缺少jar包的错误。因此,我们需要在打包时加上参数 -X 以查看具体原因:

[WARNING] The POM for com.sun.jersey:jersey-core:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey:jersey-core:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7)  @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7
[WARNING] The POM for com.sun.jersey:jersey-client:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey:jersey-client:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7)  @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7
[WARNING] The POM for com.sun.jersey.contribs:jersey-apache-client4:jar:1.19.1 is invalid, transitive dependencies (if any) will not be available: 1 problem was encountered while building the effective model for com.sun.jersey.contribs:jersey-apache-client4:[unknown-version]
[FATAL] Non-parseable POM E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom: processing instruction can not have PITarget with reserved xml name (position: END_TAG seen ...</properties>\n\n</project>\n<?xml ... @627:7)  @ E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom, line 627, column 7

特别注意FATAL这个最严重的日志级别的信息, 日志提醒我们本地仓库的pom文件E:\maven\repository\com\sun\jersey\jersey-project\1.19.1\jersey-project-1.19.1.pom解析出错,然后我们去此目录下,可以发现这个文件未被下载完整。

最后的解决方式是删除此文件的父目录,重新打包,则会自动下载一份完整的pom文件,警告消失,打包成功。

4.3 OkToRetryOnAllOperations和RequestSpecificRetryOn失效

在上文的例子中,消费者服务调用的生产者服务接口是GET类型,自动重试没有任何问题。

接着,本人尝试让消费者调用生产者服务的POST接口,同时仍然设置了ribbon.OkToRetryOnAllOperations=true,结果无法成功重试,然后去调试ribbon源码,查看自动重试机制,经查,OkToRetryOnAllOperations和RequestSpecificRetryOn属性可以成功获取到,但RequestSpecificRetryOn并未被获取出来使用,疑似Ribbon的bug。

这里记录一下调试的重要部分,

(1)Ribbon配置属性类com.netflix.client.config.CommonClientConfigKey;

(2)Ribbon判断是否重试:

所以,单独使用Ribbon需谨慎!

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于Spring-AOP实现自定义分片工具详解

    基于Spring-AOP实现自定义分片工具详解

    随着数据量的增长,在与其他系统交互时,批量接口会出现超时现象,发现原批量接口在实现时,没有做分片处理。由于与其他系统交互比较多,一个一个接口去做分片优化,改动量较大,所以考虑通过AOP解决此问题,感兴趣的可以了解一下
    2022-11-11
  • Java语言多线程终止中的守护线程实例

    Java语言多线程终止中的守护线程实例

    这篇文章主要介绍了Java语言多线程终止中的守护线程实例,具有一定借鉴价值,需要的朋友可以参考下
    2017-12-12
  • Java ThreadPool的使用解析

    Java ThreadPool的使用解析

    这篇文章主要介绍了Java ThreadPool的使用解析,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-10-10
  • Spring AOP手写动态代理代码实例

    Spring AOP手写动态代理代码实例

    这篇文章主要介绍了Spring AOP手写动态代理代码实例,AOP我们知道,是在不修改源代码的情况下,为代码添加一些新功能的技术,通过动态代理,可以在不修改原始类代码的前提下,对方法进行拦截和增强,需要的朋友可以参考下
    2024-01-01
  • Spring Boot中@Autowired注入为空的原因以及解决方法

    Spring Boot中@Autowired注入为空的原因以及解决方法

    最近在开发中遇到了使用@Autowired注解自动装配时会报空指针,发现对象并没有装配进来,下面这篇文章主要给大家介绍了关于Spring Boot中@Autowired注入为空的原因以及解决方法,需要的朋友可以参考下
    2024-01-01
  • java 非常好用的反射框架Reflections介绍

    java 非常好用的反射框架Reflections介绍

    这篇文章主要介绍了java 反射框架Reflections的使用,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Spring Boot 启动注解过程分析

    Spring Boot 启动注解过程分析

    这篇文章主要为大家介绍了Spring Boot 启动注解过程示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • @Transaction,@Async在同一个类中注解失效的原因分析及解决

    @Transaction,@Async在同一个类中注解失效的原因分析及解决

    这篇文章主要介绍了@Transaction,@Async在同一个类中注解失效的原因分析及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Springboot在有参构造方法类中使用@Value注解取值

    Springboot在有参构造方法类中使用@Value注解取值

    这篇文章主要介绍了Springboot在有参构造方法类中使用@Value注解取值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • SpringCloud openfeign声明式服务调用实现方法介绍

    SpringCloud openfeign声明式服务调用实现方法介绍

    在springcloud中,openfeign是取代了feign作为负载均衡组件的,feign最早是netflix提供的,他是一个轻量级的支持RESTful的http服务调用框架,内置了ribbon,而ribbon可以提供负载均衡机制,因此feign可以作为一个负载均衡的远程服务调用框架使用
    2022-12-12

最新评论