SpringCloud-服务间通信OpenFeignRibbon

news2024/7/4 4:28:39

服务间通信&OpenFeign&Ribbon

  • 一、服务间通信
    • 1.创建两个服务并注册到服务中心
      • 1.1.服务添加相关依赖
      • 1.2.编写配置文件application.yml
      • 1.3.入口类加上注解启动Eureka Client
    • 2.Product服务中提供调用方法
    • 3.User服务中使用RestTemplate调用
  • 二、负载均衡及Ribbon组件
    • 1.负载均衡
      • 1.1.拷贝Product服务
      • 1.2.多实例启动
    • 2.Ribbon组件
      • 2.1.Ribbon服务调用
        • 2.1.1.引入Ribbon依赖
        • 2.1.2.服务调用
    • 3.Ribbon负载均衡策略
      • 3.1.Ribbon默认负载均衡策略源码探索
      • 3.2.Ribbon负载均衡策略
      • 3.3.修改服务的默认负载均衡策略
        • 3.3.1.application.yml配置文件中修改
  • 三.OpenFeign
    • 1.OpenFeign组件
      • 1.1.OpenFeign服务调用
        • 1.1.1.引入OpenFeign依赖
        • 1.1.2.入口类加入注解开启OpenFeign支持
        • 1.1.3.创建一个客户端调用接口
        • 1.1.4. 使用FeignClient客户端对象调用服务
      • 1.2.OpenFeign超时设置


一、服务间通信

  在微服务架构中,各个微服务虽然是独立运行,独立部署,但是各个微服务间也是存在相互调用通信的情况。而在SpringCloud中通常使用Http Rest的调用方式来实现服务间的通信。
  Spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTFUL的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTFUL服务的方式。所以我们也先来使用RestTemplate实现服务间的通信。注意的是,以下使用的服务注册中心是Eureka

1.创建两个服务并注册到服务中心

User 代表用户服务 端口号为8999
Product 代表商品服务 端口号为9000

1.1.服务添加相关依赖

        <!--springboot web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--eureka client 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>

1.2.编写配置文件application.yml

#User服务配置
server:
  port: 8999

spring:
  application:
    name: USER

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址
-----------------------------------------------------------------
#Product服务配置
server:
  port: 9000

spring:
  application:
    name: PRODUCT

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址

1.3.入口类加上注解启动Eureka Client

@SpringBootApplication
@EnableEurekaClient //开启eureka客户端
public class ProductApplication {
    public static void main(String[] args){
        SpringApplication.run(ProductApplication.class, args);
    }
}

-----------------------------------------------------------------
@SpringBootApplication
@EnableEurekaClient  //开启eureka客户端
public class UserApplication {
    public static void main(String[] args){
        SpringApplication.run(UserApplication.class, args);
    }
}

2.Product服务中提供调用方法

  在Product服务中编写一段简单的测试业务代码:

@RestController
@Slf4j
public class ProductController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/product/find")
    public String find(){
        log.info("商品服务调用成功,端口为{}", port);
        return "服务调用成功,服务提供端口: " + port;
    }
}

3.User服务中使用RestTemplate调用

@RestController
@Slf4j
public class UserController {

    @GetMapping("/user")
    public String user(){
        log.info("用户服务调用成功...");
        //使用RestTemplate调用product服务
        RestTemplate restTemplate = new RestTemplate();
        //使用RestTemplate向商品服务发送Http请求调用
        String forObject = restTemplate.getForObject("http://localhost:9000/product/find", String.class);
        return forObject;
    }
}

  完成上述操作后,先启动服务注册中心服务,然后启动User和Product服务。在浏览器进入http://localhost:8761,可以发现这两个服务已经注册到Eureka服务注册中心,
在这里插入图片描述
同时,在浏览器进入http://localhost:8999/user,可以查看服务调用结果,用户服务已经成功调用了商品服务中的方法。


在这里插入图片描述
  RestTemplate是直接基于服务地址调用,并没有在服务注册中心获取服务,也没有办法完成服务的负载均衡,如果需要实现服务的负载均衡需要自己书写服务负载均衡策略,或者使用Ribbon组件。

二、负载均衡及Ribbon组件

1.负载均衡

  负载均衡,关于它的定义解释网络上有很多的博客帖子介绍,比如这篇文章:负载均衡。其实通俗的来讲,负载均衡就是尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性,不会让一个服务器处理无限制地处理任务。对于上面使用RestTemplate进行服务间的通信,它并不能实现服务间的负载均衡,所以我们可以自己定义负载均衡策略。

1.1.拷贝Product服务

  为了更能体现负载均衡的策略,我们可以将Product服务拷贝两份,并分配不同的端口并启动。首先选中需要拷贝的服务ProductApplication,然后右键单击选中Copy Configuration
在这里插入图片描述


拷贝的服务需要给定服务名,同时也需要给定端口,但是端口注意要不相同:
在这里插入图片描述

1.2.多实例启动

  拷贝完服务之后,依次启动商品服务和用户服务,将用户服务运行多次,即可发现调用的商品服务并不是都是一样的,而是随机分配的。

  当然以上的做法只是提供一个负载均衡的参考,实际的开发过程中,我们这考虑的问题还不是很周全的。比如负载均衡的策略过于单一,仅仅是采取一种随机数的策略,大多数场景中这并不适用,同时我们也无法对服务进行健康检查,不能确保服务是否可以调用。

2.Ribbon组件

  官方地址:https://github.com/Netflix/ribbon
  Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
  Ribbon实现负载均衡,其主要原理就是根据调用服务的id去服务注册中心拉取服务id的服务列表,并将服务列表拉取到本地进行缓存,然后在本地通过默认的轮询的负载均衡策略在现有的列表中选择一个可用的节点提供服务。当然默认是轮询的策略,这是可以根据需求改变的。

2.1.Ribbon服务调用

2.1.1.引入Ribbon依赖

  如果使用的是Eureka服务注册中心,那么无须引入依赖,因为在eureka中默认集成了Ribbon组件:
在这里插入图片描述
当然如果使用的client中没有Ribbon依赖,那么就需要显示地引入依赖:

<!--引入ribbon依赖-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2.1.2.服务调用

  使用LoadBalanceClient形式调用

    @Autowired
    private LoadBalancerClient loadBalancerClient;


    @GetMapping("/user")
    public String user(){
        log.info("用户服务调用成功....");
        //根据负载均衡策略选取一个服务调用
        ServiceInstance product = loadBalancerClient.choose("PRODUCT");
        log.info("服务端口:[{}]",product.getPort());
        log.info("服务地址:[{}]",product.getUri());
        //使用RestTemplate调用product服务
        RestTemplate restTemplate = new RestTemplate();
        String forObject = restTemplate.getForObject("http://" + product.getHost() + ":" + product.getPort() + "/product/find",
                String.class);
        return forObject;
    }

启动服务注册中心,并依次启动用户服务以及商品服务,浏览器进入http://localhost:8761可以查看相应服务已经注册到服务中心,
在这里插入图片描述
同时在控制台也能观察到User服务对Product服务进行调用的结果,从结果来看确实实现了负载均衡,但是它也是存在缺点的,每次的调用都需要先获取一个负载均衡机器再通过RestTemplate调用服务。
在这里插入图片描述


  使用@LoadBalanced调用
  在User服务中创建一个配置类,使用工厂模式管理RestTemplate,避免每次调用都需要重新创建一个RestTemplate对象,

@Configuration
public class RestFactory {

    @Bean
    @LoadBalanced //使对象具有Ribbon的负载均衡的特性
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
    //将RestTemplate注入
    @Autowired
    private RestTemplate restTemplate;


    @GetMapping("/user")
    public String user(){
        log.info("用户服务调用成功....");
        //使用RestTemplate调用product服务,使用服务ID获取
        String forObject = restTemplate.getForObject("http://PRODUCT/product/find", String.class);
        return forObject;
    }

启动程序运行服务同样可以实现调用负载均衡。对于@LoadBalanced实现负载均衡,其实主要的工作原理还是对添加该注解的RestTemplate会被内部LoadBalancerInterceptor拦截器拦截处理,将请求的服务名转换为具体的访问地址,再发起请求,具体的可以看看这篇文章:@LoadBalanced。

3.Ribbon负载均衡策略

3.1.Ribbon默认负载均衡策略源码探索

  对于Ribbon的默认负载均衡策略,我们可以通过对用LoadBalanceClient形式调用的代码进行debug源码追踪。在LoadBalanceClient的代码当中,我们使用loadBalancerClient.choose去获取对应服务id的其中一个服务,所以进入choose的方法当中,对于choose的实现方法,最终会进入到RibbonLoadBalancerClient的实现类,
在这里插入图片描述

进入choose的实现方法中,我们再进入this.getServer的方法,查看其获取服务的过程,之后再次

在这里插入图片描述

进入chooseServer的方法中,对于chooseServer有三个实现类,采用debug确定进入的是

在这里插入图片描述

ZoneAwareLoadBalancer这个实现类,

在这里插入图片描述

最终在return中进入到 BaseLoadBalancer.class中的chooseServer方法中,

在这里插入图片描述

继续往下调试,我们也不难发现,key的值是default,在最后的choose中确定了负载均衡策略,而且是默认的策略rule,我们在代码定义中可以发现rule变量,其中就包括了默认的负载均衡策略,

在这里插入图片描述

就是RoundRobinaRule,即轮询策略。

在这里插入图片描述

3.2.Ribbon负载均衡策略

  Ribbon除了默认的轮询策略,还有其他几种策略一样可以配置使用。对于其他的负载均衡策略,我们同样可以在代码中寻找到,有了上面的源码探索,我们可以知道负载策略的最高层级的接口是IRule,对于其实现类在这使用的是AbstractLoadBalancerRule.class,因此我们可以将它们的逻辑图展示出来,
在这里插入图片描述
在这对这七种策略进行简单的介绍:

RandomRule随机策略 会随机选择服务
RoundRobinRule轮询策略 按顺序循环选择服务
RetryRule重试策略 先按照RoundRobinRule的策略获取服务,如果获取失败则在指定时间内进行重试,获取可用的服务
PredicateBasedRule它先通过内部定义的一个过滤器过滤出一部分服务实例清单,然后再采用线性轮询的方式从过滤出来的结果中选取一个服务实例
BestAviableRule最低并发策略 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
WeightedResponseTimeRule响应时间加权策略 根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高,刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够会切换回来
AvailabilityFilteringRule可用过滤策略 会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
ZoneAvoidanceRuleZoneAvoidanceRule中的过滤条件是以ZoneAvoidancePredicate为主过滤条件和以AvailabilityPredicate为次过滤条件组成的一个叫做CompositePredicate的组合过滤条件,过滤成功之后,继续采用线性轮询的方式从过滤结果中选择一个出来

3.3.修改服务的默认负载均衡策略

  Ribbon虽然定义了默认的负载均衡策略,但是我们同样可以去修改它的策略配置实现自己的需求。同时需要注意,以下提到的方法只是对局部有效,并不作用于全局。

3.3.1.application.yml配置文件中修改

#修改服务默认的负载均衡策略样例
PRODUCT:
  ribbon:
  #修改为随机策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

------------------------------------------------------------------------------------
serverName: #代表要调用的服务名
  ribbon:
  #xxxx代表需要替换的上述提到的七种策略的其他策略名
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.xxxx


三.OpenFeign

  服务间的调用我们已经可以使用RestTemplate及Ribbon完成,但是对于它们的使用还是存在一些不足:

  • 1.每次调用服务都需要写类似代码,存在大量的代码冗余
  • 2.服务地址如果修改,维护成本增高
  • 3.使用时不够灵活

所以OpenFeign组件的引入可以使得服务间的调用更高效。

1.OpenFeign组件

  官网地址:OpenFeign
  Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,默认实现了负载均衡的效果并且SpringCloud为Feign添加了SpringMVC注解的支持。

1.1.OpenFeign服务调用

1.1.1.引入OpenFeign依赖

  在服务的调用方加入OpenFeign的依赖,本例中则是在User服务中添加该依赖。

        <!--Open Feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

1.1.2.入口类加入注解开启OpenFeign支持

@SpringBootApplication
@EnableEurekaClient  //开启eureka客户端
@EnableFeignClients  //开启Feign支持
public class UserApplication {
    public static void main(String[] args){
        SpringApplication.run(UserApplication.class, args);
    }
}

1.1.3.创建一个客户端调用接口

  在User服务中创建一个包存专门放Feign调用接口,同时在其中创建调用接口:

//value属性用来指定:调用服务名称
@FeignClient(value = "PRODUCT")
public interface ProductClient {

    @GetMapping("/product/find") 书写服务调用路径
    public String find();
}

1.1.4. 使用FeignClient客户端对象调用服务

@RestController
@Slf4j
public class UserController {

    @Autowired
    private ProductClient productClient;

    @GetMapping("/user")
    public String user(){
        log.info("用户服务调用成功....");
        String msg = productClient.find();
        return msg;
    }
}

1.2.OpenFeign超时设置

  默认情况下,OpenFiegn在进行服务调用时,要求服务提供方处理业务逻辑时间必须在1S内返回,如果超过1S没有返回则OpenFeign会直接报错,不会等待服务执行,但是往往在处理复杂业务逻辑是可能会超过1S,因此需要修改OpenFeign的默认服务调用超时时间。

#xxxx代表被调用的服务名
feign.client.config.xxxx.connectTimeout=5000  		#配置指定服务连接超时
feign.client.config.xxxx.readTimeout=5000		  	#配置指定服务等待超时
feign.client.config.default.connectTimeout=5000  		#配置所有服务连接超时
feign.client.config.default.readTimeout=5000			#配置所有服务等待超时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/513346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《三》包管理工具

包管理工具 npm&#xff1a; npm&#xff1a;Node Package Manager&#xff0c;Node 包管理器&#xff0c;目前已经不仅仅作为 Node 的包管理工具&#xff0c;也作为前端的包管理工具来管理包。 npm 管理的包是存放在一个名为 registry 的仓库中的&#xff0c;发布一个包时是…

AI歌手——超简单一键运用ACE Studio来训练模拟真人唱歌

目录 1.安装ACE Studio 2.打开ACE Studio 3.导入midi或音频 4.调试音频 5.调整人物音色音高 6.调整歌词 7.自动添加呼吸​编辑 8.成品演示&#xff08;周杰伦の稻香——鲤阮&#xff09; 1.安装ACE Studio 安装地址 ACE Studio | Create Limitless Vocals with AI (t…

如何用AI画56个民族的女孩!

大家好&#xff0c;我是菜鸟哥&#xff01; 目前在带领600多个小伙伴一起玩AI&#xff01;Chatgpt现在是最火最出圈的产品&#xff0c;而一旦文字和图像&#xff0c;声音&#xff0c;视频结合可以演化出很多很多的需求。前面我们公众号已经分享了很多很多关于chatgpt的使用和技…

大势智慧软硬件技术答疑第二期

1. 编辑模型视图为什么是空的呢&#xff1f;工程这里也选了obj数据位置。 答&#xff1a;CtrlT选择下瓦块就可以&#xff0c;或者点这个图标。 2. 支持编辑DSM 生成正射吗&#xff1f; 答&#xff1a;重建大师&#xff0c;模方&#xff0c;和dasview均支持直接生产正射和DSM&a…

idea-properties文件编码为iso-8859-1修改为utf-8

一、现状 idea中properties文件编码为iso-8859-1并且为灰色不可修改 二、修改成utf-8 command,打开preferences 如下图操作即可

机器学习——logit正则化

机器学习——logit正则化 文章目录 机器学习——logit正则化[toc]1 logit模型正则化2 logit回归求解器2.1 ℓ 1 \ell_1 ℓ1​和 ℓ 2 \ell_2 ℓ2​正则化2.2 e l a s t i c − n e t elastic-net elastic−net正则化 1 logit模型正则化 logit模型能实现分类&#xff0c;识别…

励志长篇小说《周兴和》书连载之四 屋漏偏遇连天雨

屋漏偏遇连天雨 周兴和的母亲就死于那个寒冷的冬天。 她死时是1969年农历正月十八的早晨。 这时&#xff0c;周兴和的大女儿刚出生40多天。 母亲的病其实已经拖了好长时间了。刚开始她还能起床给一家人做饭&#xff0c;干点轻微的家务事。渐渐地&#xff0c;她开始不能吞食东…

如何成为年薪70万的全栈开发和测试人员?必备技能一网打尽

目录 引言 什么是全栈开发人员&#xff1f; 为什么需要全栈开发人员&#xff1f; 成为Full Stack Developer所需的技能组合 什么是软件栈&#xff1f; LAMP栈 MERN是基于JavaScript的技术的集合&#xff1a; Full Stack Developer的职责 技术的准备 一、测试基础 二…

面试官常问的音视频技术点!

一、前言&#xff1a; 今天继续给大家分享最近星球上的星友音视频面试题目&#xff0c;希望对大家有用&#xff01; 下面是具体面试问的问题&#xff1a; 二、面试题目&#xff1a; 1、请说下H264的两种形态&#xff1a; Annex B格式&#xff1a;这种格式常用于网络流媒体传输…

yum源下载,及安装本地rpm包

yum源下载&#xff1a; yumdownloader rpm包名 如 &#xff1a;要下载 关于 pcre2-devel的包&#xff0c; 发现需要 依赖&#xff1a; Downloading packages: (1/4): pcre2-10.23-2.el7.x86_64.rpm | 20…

架构师备战(一)-软考如何备考

我要备战的是系统架构设计师&#xff0c;那么软考有哪些可供我们选择的考试呢。 1、软考能考哪些 我们知道&#xff0c;软考的体系结构有很多&#xff0c;比如初级的程序员&#xff0c;中级的软件设计师&#xff0c;高级的系统架构师等。具体有哪些&#xff0c;大概有如下这些…

华硕ROG STRIX B760-G GAMING WIFI小吹雪D5评测:最能超的小主板 轻松提升14%

一、前言&#xff1a;华硕推出新版B760-G小吹雪主板 加入DDR5内存支持 和以往的每一代规格一样&#xff0c;DDR5内存上市初期的表现并不如人意&#xff0c;频率是高了&#xff0c;但延迟也高了&#xff0c;导致性能提升一般般。 经过一两年的演进&#xff0c;DDR5内存的时序延迟…

港联证券|熊市牛市出现的原因?出现时应该怎么办?

熊市和牛市是股市专业术语&#xff0c;都指的是股市的一种形式。那么熊市牛市出现的原因&#xff1f;出现时应该怎么办&#xff1f;下面就由港联证券为大家进行分析&#xff1a; 熊市牛市出现的原因&#xff1f; 熊市出现原因&#xff1a; 1、市场利空消息出现 比如公司业绩…

【Spring框架全系列】SpringBoot配置日志文件

&#x1f367;&#x1f367;哈喽&#xff0c;大家好&#xff0c;我是小浪。那么上篇博客我们学习了SpringBoot配置文件的相关操作&#xff0c;本篇博客我们将学习一个新的知识点&#xff0c;SpringBoot日志文件。&#x1f5a5;&#x1f5a5; &#x1f4f2;目录 一、日志是什么…

Git概念介绍,常用命令与工作流程整理 配图

首先附一张Git的cheat sheet 作为开始&#xff0c;方便查阅&#xff1a;https://education.github.com/git-cheat-sheet-education.pdf Git简介 Git大家肯定都不陌生了&#xff0c;象征性地再介绍一下&#xff1a;Git是一个版本控制系统&#xff0c;换句话说&#xff0c;它可…

TypeError: makedirs() got an unexpected keyword argument ‘exist_ok‘

背景&#xff1a; 自己在使用pyinstaller打包一个基于pyqt5的gan网络手写数字生成的项目的时候&#xff0c;打包过程中出现这个错误导致打包失败。 图示&#xff1a; 问题分析&#xff1a; 复制这个错误在百度上搜看到很多答案说是python版本的原因。2.7版本的python不支持…

Redis如何存储一个Java对象【内涵案例】

目录 Java原生序列化示例 GSON示例 使用fastjson存储Java对象到Redis时 Redis并不能直接存储Java对象&#xff0c;需要进行序列化或者转换成字符串等格式才可以进行存储。以下介绍两种常见的将Java对象存储到Redis的方案。 对象序列化&#xff0c;存储二进制数据 将对象进…

使用Chatglm-6b微调催收问答对的尝试

1.工作目录&#xff0c;如&#xff1a;mnt/d/work&#xff0c;下载源代码&#xff0c;并安装依赖 git clone https://github.com/THUDM/ChatGLM-6B cd ChatGLM-6B pip install -r requirement.txt 2. 从拥抱脸下载chatglm-6b-int4-qe到本地&#xff08;GPU环境搭建参考浪潮服…

线性结构-栈

栈是Stack一个后进先出Last In First Out,LIFO的线性表&#xff0c;他要求只在表尾对数据执行删除和插入等操作。 栈就是一个线性表&#xff0c;可以是数组、也可以是链表。但它的操作有别于一般的线性表。栈的元素必须先进后出&#xff0c;也就是先进入栈的元素必须后出栈。而…

金三银四好像消失了,IT行业何时复苏

疫情时候不敢离职&#xff0c;以为熬过来疫情了&#xff0c;行情会好一些&#xff0c;可是疫情结束了&#xff0c;反而行情更差了&#xff0c; 这是要哪样 我心中不由一万个 草泥&#x1f434; 路过 我心中不惊有了很多疑惑和感叹 接着上一篇 一个28岁程序员入行自述和感受 自…