微服务篇-C 深入理解第一代微服务(SpringCloud)_III 深入理解Ribbon负载均衡和Feign远程服务调用

原创作者:田超凡(程序员田宝宝)

版权所有,引用请注明原作者,严禁复制转载

Part 1 理论部分

1 什么是客户端负载均衡?

在SpringCloud中,使用Ribbon作为负载均衡客户端实现客户端负载均衡。

Ribbon会从Eureka注册中心服务器端获取服务注册信息列表,然后会缓存到本地,在本地通过轮询、取模、权重、一致性Hash、随机权重、随机等策略实现客户端负载均衡。

2 Ribbon和Nginx的区别?

1 使用环境的区别

Ribbon实现的是客户端负载均衡:

Ribbon是从Eureka注册中心服务器端中获取服务注册信息列表,然后缓存到本地,在本地通过轮询等策略实现负载均衡。

所以Ribbon属于客户端负载均衡,即在客户端本地实现的负载均衡。

Nginx实现的是服务器端负载均衡:

Nginx运行在服务器端,客户端会将所有发送到服务器的请求统一交给Nginx,由Nginx在服务器端实现负载均衡请求转发。

所以Nginx属于服务器端负载均衡,即请求到达服务器之后,由Nginx在服务器上进行转发。

2 应用场景的区别

Ribbon适用于微服务客户端,通过RPC远程服务调用对需要请求的缓存在本地的服务地址列表实现负载均衡的场景,比如在Dubbo、SpringCloud中,服务调用都是采用的客户端负载均衡。

Nginx适用于在服务器端实现负载均衡请求转发的场景,比如Tomcat。

3 什么是Feign?什么是OpenFeign?

Feign客户端是一个Web声明式的、基于HTTP协议的RPC远程服务调用工具,提供了接口和注解等方式方便灵活进行RPC远程服务调用,Feign默认已经整合了Ribbon负载均衡客户端。

OpenFeign是在Feign基础上重新封装的一个支持SpringMVC注解的(比如
@RequestMapping等)RPC远程服务调用工具。

Part 2 实践部分

使用discoveryClient负载本地负载均衡

@Autowired

      private MemberApifeign memberApifeign;

      @RequestMapping("/feignMember")

      public String feignMember() {

            return memberApifeign.getMember();

      }

      private int requestCount = 1;

      @RequestMapping("/discoveryClient")

      public String discoveryClient() {

            String serviceUrl = getServiceUrl() + "/getMember";

            if (StringUtils.isEmpty(serviceUrl)) {

                  return "请求地址为null";

            }

            // 请求地址

            System.out.println("serviceUrl:" + serviceUrl);

            String result = restTemplate.getForObject(serviceUrl, String.class);

            return result;

      }

      @RequestMapping("/getServiceUrl")

      private String getServiceUrl() {

            List<ServiceInstance> instances = discoveryClient.getInstances("app-ittcf-member");

            if (instances == null || instances.size() == 0) {

                  return null;

            }

            int size = instances.size();

            int index = requestCount % size;

            requestCount++;

            return instances.get(index).getUri().toString();

      }

RestTemplate

请求类型

GET请求

getForEntity

getForEntity方法的返回值是一个ResponseEntity<T>,ResponseEntity<T>是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等

@RequestMapping("/getForEntity")

      public ResponseEntity<String> getForEntity() {

            ResponseEntity<String> response = restTemplate.getForEntity("http://app-ittcf-member/getMember",

                        String.class);

            System.out.println("statusCode:" + response.getStatusCode());

            System.out.println("Body:" + response.getBody());

            return response;

      }

getForEntity的第一个参数为我要调用的服务的地址,这里我调用了服务提供者提供的/hello接口,注意这里是通过服务名调用而不是服务地址,如果写成服务地址就没法实现客户端负载均衡了。

getForEntity第二个参数String.class表示我希望返回的body类型是String

拿到返回结果之后,将返回结果遍历打印出来

Get请求传递参数

      @RequestMapping("/getForOrderEntity2")

      public ResponseEntity<String> getForEntity2(String name) {

            Map<String, String> map = new HashMap<String, String>();

            map.put("name", name);

            ResponseEntity<String> response = restTemplate.getForEntity("http://app-ittcf-member/getUser?name={name}",

                        String.class, map);

            System.out.println("statusCode:" + response.getStatusCode());

            System.out.println("Body:" + response.getBody());

            return response;

      }

可以用一个数字做占位符,最后是一个可变长度的参数,来一一替换前面的占位符

也可以前面使用name={name}这种形式,最后一个参数是一个map,map的key即为前边占位符的名字,map的value为参数值

getForObject

getForObject函数实际上是对getForEntity函数的进一步封装,如果你只关注返回的消息体的内容,对其他信息都不关注,此时可以使用getForObject,举一个简单的例子,如下:

@RequestMapping("/getOrder")

      public String getOrder() {

            // 有两种实现方式,一种是采用服务别名方式调用,另一种是直接调用使用别名去注册中心上获取对应的服务调用地址

            String url = "http://app-ittcf-member/getMember";

            String result = restTemplate.getForObject(url, String.class);

            System.out.println("订单服务调用用户服务:" + result);

            return result;

      }

POST请求
PostForEntity
postForObject

如果你只关注,返回的消息体,可以直接使用postForObject。用法和getForObject一致

PUT请求
DELETE请求

声明式服务调用SpringCloud Feign

feign介绍

Feign客户端是一个web声明式http远程调用工具,提供了接口和注解方式进行调用。

环境搭建

Maven依赖信息

   <dependency>

          <groupId>org.springframework.cloud</groupId>

          <artifactId>spring-cloud-starter-openfeign</artifactId>

      </dependency>

feign客户端接口

   @Autowired

   private MemberApifeign memberApifeign;

   @RequestMapping("/feignMember")

   public String feignMember() {

      return memberApifeign.getMember();

   }

feign客户端接口

// name 指定服务名称

@FeignClient(name = "app-ittcf-member")

public interface MemberApifeign {

   @RequestMapping("/getMember")

   public String getMember();

}

项目启动加上@EnableFeignClients

@SpringBootApplication

@EnableEurekaClient

@EnableFeignClients

public class AppOrder {

   public static void main(String[] args) {

      SpringApplication.run(AppOrder.class, args);

      // 如果使用rest方式以别名方式进行调用依赖ribbon负载均衡器 @LoadBalanced

      // @LoadBalanced就能让这个RestTemplate在请求时拥有客户端负载均衡的能力

   }

   // 解决RestTemplate 找不到原因 应该把restTemplate注册SpringBoot容器中 @bean

   @Bean

   @LoadBalanced

   RestTemplate restTemplate() {

      return new RestTemplate();

   }

}

feign继承特性

在使用声明式feign客户端工具的时候,因为书写的方式代码可能会产生重复,可以使用feign客户端集成方式减少代码。

创建springcloud-2.0-parent

  Maven依赖信息

<parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>2.0.1.RELEASE</version>

    </parent>

    <!-- 管理依赖 -->

    <dependencyManagement>

        <dependencies>

             <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-dependencies</artifactId>

                 <version>Finchley.M7</version>

                 <type>pom</type>

                 <scope>import</scope>

             </dependency>

        </dependencies>

    </dependencyManagement>

    <dependencies>

        <!-- SpringBoot整合Web组件 -->

        <dependency>

             <groupId>org.springframework.boot</groupId>

             <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <!-- SpringBoot整合eureka客户端 -->

        <dependency>

             <groupId>org.springframework.cloud</groupId>

             <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

        </dependency>

        <!-- SpringBoot整合fegnin客户端 -->

        <dependency>

             <groupId>org.springframework.cloud</groupId>

             <artifactId>spring-cloud-starter-openfeign</artifactId>

        </dependency>

        <dependency>

             <groupId>org.projectlombok</groupId>

             <artifactId>lombok</artifactId>

        </dependency>

    </dependencies>

    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->

    <repositories>

        <repository>

             <id>spring-milestones</id>

             <name>Spring Milestones</name>

             <url>https://repo.spring.io/libs-milestone</url>

             <snapshots>

                 <enabled>false</enabled>

             </snapshots>

        </repository>

    </repositories>

创建springcloud-2.0-api
创建springcloud-2.0-member-api
创建springcloud-2.0-order-api
创建springcloud-2.0-member
application.yml

###服务启动端口号

server:

  port: 8000

###服务名称(服务注册到eureka名称

spring:

    application:

        name: app-ittcf-member

###服务注册到eureka地址

eureka:

  client:

    service-url:

           defaultZone: http://localhost:8100/eureka

          

###因为该应用为注册中心,不会注册自己

    register-with-eureka: true

###是否需要从eureka上获取注册信息

    fetch-registry: true

创建springcloud-2.0-order
application.yml

###服务启动端口号

server:

  port: 8001

###服务名称(服务注册到eureka名称

spring:

    application:

        name: app-ittcf-order

###服务注册到eureka地址

eureka:

  client:

    service-url:

           defaultZone: http://localhost:8100/eureka

          

###因为该应用为注册中心,不会注册自己

    register-with-eureka: true

###是否需要从eureka上获取注册信息

    fetch-registry: true

Ribbon配置

SpringCloud Feign客户端Http调用工具,默认已经整合了Ribbon负载均衡客户端。

配置Feign客户端超时时间

###设置feign客户端超时时间

ribbon:

###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。

 ReadTimeout: 5000

###指的是建立连接后从服务器读取到可用资源所用的时间。

 ConnectTimeout: 5000

本文部分素材转载自蚂蚁课堂

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

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

相关文章

前端面试拼图-知识广度

摘要&#xff1a;最近&#xff0c;看了下慕课2周刷完n道面试题&#xff0c;记录并添加部分可参考的文档&#xff0c;如下... 1. 移动端H5 click有300ms延迟&#xff0c; 如何解决&#xff1f; 背景&#xff1a;double tap to zoom 移动端H5中的300ms点击延迟问题通常是由浏览…

从零开始学习在VUE3中使用canvas(三):font(字体)

一、简介 我们可以使用font在canvas中绘制文字&#xff0c;方式如下: const ctx canvas.getContext("2d"); // 绘制文字 ctx.font "24px 黑体, 宋体"; //字体大小 首选字体 备选字体 ctx.fillText("这里是显示的字的内容", 100, 50); //文字…

python--高阶函数

python--高阶函数 mapmap的用法map的代码示例 filterfilter的用法filter的代码示例 reducereduce的用法reduce的代码示例 返回函数IO编程打开文件文件打开--打开格式文件打开--上下文管理器打开文件&#xff08;会自动close文件&#xff09; 文件读取文件读取--file.read(m)文件…

反射计数(100%用例)(JavaPythonC++Node.jsC语言)

给定一个包含0和1的二维矩阵 给定一个初始位置和速度 一个物体从给定的初始位置触发,在给定的速度下进行移动,遇到矩阵的边缘则发生镜面反射 无论物体经过0还是1,都不影响其速度 请计算并给出经过t时间单位后,物体经过1点的次数 矩阵以左上角位置为[0,0](列(x),行(行)),例如下面…

全量知识系统 微服务及特征复数空间和立体逻辑方阵的设想及SmartChat回复

Q1..一个立方逻辑方阵给出全量知识有关的8个复合逻辑之间的真假制约关系&#xff0c;是 设计中的“全量知识系统”程序化的基础。理解这句话&#xff0c;并使用一个立方逻辑方阵来描述“全量知识系统”中全量知识的量纲化的程序结构&#xff0c;作为全量知识系统中量纲原型的一…

[QJS xmake] 非常简单地在Windows下编译QuickJS!

文章目录 前言准备C编译器xmake编译包 工程准备修改版本号第一遍编译第二遍编译效果 前言 quickjs是个很厉害的东西啊&#xff0c;我一直想编译一下的&#xff0c;奈何一直没成功。现在找了点时间成功编译了&#xff0c;写篇文章记录一下。当前版本&#xff1a;2024-1-13 应该…

数组练习oj

数组练习 合并两个有序数组——排序法 class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {for(int i 0; i < n; i){nums1[mi] nums2[i];}sort(nums1.begin(), nums1.end());} };删除有序数组中的重复性—…

OkHttp

文章目录 OkHttp概要1.简介2.特点3.基本组成5.工作流程 拦截器1.简介2.内置拦截器3.自定义拦截器 连接池1.简介2.常用参数配置选项 Dispatcher和线程池1.简介2.重要方法3.DispatCher中的双端队列4.总结 OkHttp 概要 1.简介 OkHttp是一个开源的HTTP客户端&#xff0c;用于在J…

对象的一些概念

一.对象的定义 1.在声明类的同时定义类: 但这定义的是全局变量,一定要少使用 class Point{public:void setPoint(int a,int b){xa,yb;}int getx(){return x;}int getx(){return y;} private:int x,y;};op1,op2; 2.声明类后,在使用时定义对象 class Point{... };main() …

全量知识系统“全基因序列”程序构想及SmartChat的回复

感觉上&#xff0c;全量知识系统的程序起点基本确定。下一步就是程序了。程序的整个设计过程都准备同时使用两个AI工具。以下是和“百度AI”同步进行的Q&A。 Q1. 基本假设&#xff1a;“全基因序列”中“基因”的本质是联结collection。 做法是&#xff1a; 对给出的一个…

留学文书可以彻底被AI取代吗?升学指导这一职业是否会被AI逼到墙角?

近日&#xff0c;ChatGPT再次“进化”&#xff0c;其最新版本ChatGPT-4又掀高潮。其生产者OpenAI 称&#xff0c;“ChatGPT-4是最先进的系统&#xff0c;能生产更安全和更有用的回复。”和上一代相比&#xff0c;GPT-4拥有了更广的知识面和更强的解决问题能力&#xff0c;在创意…

机器学习_聚类(k-means)

文章目录 聚类步骤k-means APIKmeans性能评估指标Kmeans性能评估指标API 聚类步骤 k-means通常被称为劳埃德算法&#xff0c;这在数据聚类中是最经典的&#xff0c;也是相对容易理解的模型。算法执行的过程分为4个阶段。 1.首先&#xff0c;随机设K个特征空间内的点作为初始的…

详细分析Mysql中的LOCATE函数(附Demo)

目录 1. 基本概念2. Demo3. 实战 1. 基本概念 LOCATE()函数在SQL中用于在字符串中查找子字符串的位置 它的一般语法如下&#xff1a; LOCATE(substring, string, start)LOCATE()函数返回子字符串在主字符串中第一次出现的位置 如果未找到子字符串&#xff0c;则返回0 具体的…

Vue/Uni-app/微信小程序 v-if 设置出场/退出动画(页面交互不死板,看起来更流畅)

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 在Vue.js中&#xff0c;使用v-if进行条件渲染时设置动画可以通过<transition>组件来实现。 具体操作步骤如下&#xff1a; 包裹条件渲染的元素&#xff1a;您需要将要通过v-if控制显示隐藏的元素包裹在<transition…

keil软件不能连接STM32,烧录程序无法执行

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 问题现象解决方法 问题现象 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 最近在学习江科大的STM32的时候&#xff0c;学到11-2 硬件SPI读写W2…

【环境搭建】Ubuntu16 C++

1. CMake 下载软件包 下载地址 解压文件 检查依赖 ./bootstrap Q1: CMake Error at Utilities/cmcurl/CMakeLists.txt:647 (message): Could not find OpenSSL. Install an OpenSSL development package or configure CMake with -DCMAKE_USE_OPENSSLOFF to build without Op…

跳绳计数,YOLOV8POSE

跳绳计数&#xff0c;YOLOV8POSE 通过计算腰部跟最初位置的上下波动&#xff0c;计算跳绳的次数

HTML静态网页成品作业(HTML+CSS)——个人介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

Linux:Gitlab:16.9.2 (rpm包) 部署及基础操作(1)

1.基础环境 我只准备了一台gitlab服务器&#xff0c;访问就用真机进行访问&#xff0c;接下来介绍一下详细配置 centos7 内网ip:192.168.6.7 外网ip:172.20.10.4 运行内存&#xff1a;4G CPU:4核 先去配置基础环境 关闭防火墙以及selinux 再去下载基础的运行…

flutter使用记录(vscode开发)

1.Gradle-7.6.3-all.zip 下载失败 编辑项目中的 gradle/wrapper/gradle-wrapper.properties 文件&#xff0c;并设置 distributionUrl 的值为可靠的镜像站点&#xff0c;如下所示&#xff1a; distributionUrlhttps\://services.gradle.org/distributions/gradle-7.6.3-all.z…