当前位置: 首页 > news >正文

微服务之OpenFeign、hystrix熔断降级、loadbalancer负载均衡

微服务学习顺序:
微服务之Nacos
微服务之OpenFeign
微服务之网关

简介

微服务架构中使用OpenFeign进行服务间的相互调用,OpenFeign提供了一种简洁的方式来定义和处理服务间的调用。OpenFeign作为一个声明式的、模块化的HTTP客户端,通过「接口」的定义和「注解」的使用,简化了微服务之间的通信调用。

OpenFeign 能自动根据服务名找到目标服务的网络地址,实现跨服务的 HTTP 通信。

案例openfeign

子项目bill-7780准备接口

此处项目在我的另一篇文章中的项目的基础上进行创建:微服务之Nacos

在子项目bill-7780的SmbmsBillService中添加根据供应商id查询接口方法

package com.lp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.lp.entity.SmbmsBill;
import com.lp.utils.ResultAJAX;public interface SmbmsBillService extends IService<SmbmsBill> {public ResultAJAX findList();public ResultAJAX findListByProId(Integer id);}

实现该接口方法

package com.lp.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lp.entity.SmbmsBill;
import com.lp.mapper.SmbmsBillMapper;
import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.stereotype.Service;@Service
public class SmbmsBillServiceImpl extends ServiceImpl<SmbmsBillMapper, SmbmsBill> implements SmbmsBillService {@Overridepublic ResultAJAX findList() {return ResultAJAX.success(this.list());}@Overridepublic ResultAJAX findListByProId(Integer id) {return ResultAJAX.success(this.list(new QueryWrapper<SmbmsBill>().eq("providerId",id)));}
}

创建一个api包,用于专门对外提供接口。创建BillServiceAPI,此时只是一个普通的controller。

package com.lp.api;import com.lp.service.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/billApi")
public class BillServiceAPI {@Autowiredprivate SmbmsBillService smbmsBillService;@GetMapping("/listByProId")public ResultAJAX listByProId(@RequestParam("id") Integer id){ //必须添加@RequestParam注解System.out.println("id==="+id);return smbmsBillService.findListByProId(id);}}

在这里插入图片描述

子项目provider-7790调用接口

以前分布式中如果我们想在provider-7790中调用bill-7780中的接口,需要在provider-7790的pom文件中中引入bill-7780。

但现在项目provider-7790和项目bill-7780应该是互相独立没有关联的(比如这两个项目分别部署在不同的电脑或服务器上),是没有办法在provider-7790的pom文件中引入bill-7780,并调用bill-7780提供的接口。

这时就需要用到远程调用了,用子项目provider-7790调用上面bill-7780中创建的BillServiceAPI中的接口方法。

修改application.yml文件,注册中心端口配置改为8850

server:port: 7790
spring:application:name: provider-7790 #往注册中心放的服务名称,一般与项目名保持一致(服务名称不能重复)cloud:nacos:discovery:server-addr: 127.0.0.1:8850username: nacospassword: nacos

OpenFeign 是 Spring Cloud 的组件,而非 Spring Cloud Alibaba 的组件。按步骤(1、2、3)在父级项目cloud-alibaba-test的pom文件引入OpenFeign依赖。

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>cloud-alibaba-test</artifactId><version>0.0.1-SNAPSHOT</version><name>cloud-alibaba-test</name><description>cloud-alibaba-test</description><!--指定子模块--><modules><module>bill-7780</module><module>provider-7790</module><module>cloud-common</module></modules><!--指定父级项目打包方式--><packaging>pom</packaging><properties><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.6</spring-boot.version><!--1. 指定Spring Cloud版本--><spring-cloud.version>2021.0.5</spring-cloud.version><spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version></properties><dependencies><!--3. 引入OpenFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!--2. 引入Spring Cloud依赖管理(核心) --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.cloudalibabatest.CloudAlibabaTestApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

在父级项目cloud-alibaba-test引入负载均衡loadbalancer依赖(无论是否用到负载均衡,若想使用OpenFeign就必须引入loadbalancer依赖)

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

在子项目provider-7790的pom文件中引入cloud-common公共内容(为了使用公共返回类ResultAJAX)

<dependency><groupId>com.lp</groupId><artifactId>cloud-common</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

创建service.api包,并创建远程调用接口(创建api包是用于把这个项目自己的service和远程调用的service区分开来)该接口不需要写实现,它的实现就是在前面子项目bill-7780中创建的BillServiceAPI(需要加注解@FeignClient

package com.lp.service.api;import com.lp.utils.ResultAJAX;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(name = "bill-7780") //name:为服务提供者的服务名
public interface SmbmsBillService {@GetMapping("/billApi/listByProId")//要与BillServiceAPI类中的方法使用的请求方式一致,比如均为@GetMapping或@RequestMappingpublic ResultAJAX listByProId(@RequestParam("id") Integer id); //必须添加@RequestParam注解
}

如果要调用的接口方法很多,就如上面的@GetMapping("/billApi/listByProId"),每次都要写/billApi,很麻烦。可以在@FeignClient注解中添加path属性,如:@FeignClient(name = "bill-7780", path = "billApi"),这样可以简化方法上的如@GetMapping注解中的请求路径的书写:在这里插入图片描述

在这里插入图片描述
创建控制器

package com.lp.controller;import com.lp.service.api.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/bill")
public class SmbmsBillController {@Autowiredprivate SmbmsBillService smbmsBillService;@GetMapping("/listByProId")public ResultAJAX listByProId(Integer id){return smbmsBillService.listByProId(id);}}

在这里插入图片描述

在启动类添加注解@EnableFeignClients,开启OpenFeign。

package com.lp;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients
public class Provider7790Application {public static void main(String[] args) {SpringApplication.run(Provider7790Application.class, args);}}

启动项目,测试远程访问接口

首先要保证nacos开启,启动启动项目bill-7780和项目provider-7790,浏览器访问http://localhost:7790/bill/listByProId?id=1
在这里插入图片描述
会发现我们访问的是provider-7790的接口方法,但内部会远程访问bill-7780的接口方法。
在这里插入图片描述
在这里插入图片描述

hystrix熔断降级

前面我们是通过provider-7790调用的bill-7780的接口方法,那么可能会出现一种情况就是provider-7790调不到bill-7780中的接口方法(比如说bill-7780服务挂掉了),调不到就会报错,前端页面就会显示500错误,这不是我们想要的。我们想要美化或者说处理一下这个错误,这就需要用到熔断降级了。在调用者(比如provider-7790)中添加降级处理。
在这里插入图片描述
在子项目provider-7790的pom文件中引入依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.2.9.RELEASE</version>
</dependency>

在配置文件中开启服务降级:

server:port: 7790
spring:application:name: provider-7790 #往注册中心放的服务名称,一般与项目名保持一致(服务名称不能重复)cloud:nacos:discovery:server-addr: 127.0.0.1:8850username: nacospassword: nacos
feign:circuitbreaker:enabled: true # 开启熔断处理

编写前面provider-7790中service.api包下SmbmsBillService的实现,一旦远程调用失败,就会自动执行该实现类下的方法

package com.lp.service.api.impl;import com.lp.service.api.SmbmsBillService;
import com.lp.utils.ResultAJAX;
import org.springframework.stereotype.Component;//降级处理:如果服务提供者挂了,则调用此降级处理类
//要添加@Component注解,不用@Service是因为它是Spring中用于标识业务逻辑层组件的注解(其实能用),而@Component语义更通用,用于标识任意受Spring管理的组件
@Component
public class SmbmsBillServiceImpl implements SmbmsBillService {@Overridepublic ResultAJAX listByProId(Integer id) {return ResultAJAX.error("接口调用失败,服务降级处理。。。");}
}

虽然SmbmsBillServiceImpl是SmbmsBillService的实现,但它不是务逻辑层,我们不会用@Service,而是用语义更通用的@Component。

在这里插入图片描述

修改SmbmsBillService接口中@FeignClient,使用fallback属性指定服务降级处理

package com.lp.service.api;import com.lp.service.api.impl.SmbmsBillServiceImpl;
import com.lp.utils.ResultAJAX;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(name = "bill-7780", path = "billApi", fallback = SmbmsBillServiceImpl.class) //name:为服务提供者的服务名
public interface SmbmsBillService {@GetMapping("/listByProId")//要与BillServiceAPI类中的方法使用的请求方式一致,比如均为@GetMapping或@RequestMappingpublic ResultAJAX listByProId(@RequestParam("id") Integer id); //必须添加@RequestParam注解
}

启动项目bill-7780和项目provider-7790(需要nacos处在启动状态),浏览器访问http://localhost:7790/bill/listByProId?id=1,访问成功
在这里插入图片描述

关闭项目bill-7780,再次访问http://localhost:7790/bill/listByProId?id=1,模拟接口调用失败
在这里插入图片描述
会发现降级处理起作用了。

loadbalancer负载均衡

假如消费者(如provider-7790)请求调用提供者(如bill-7780)的提供的接口,一个提供者压力太大,为了均衡,再加一个提供者,在消费者中做负载均衡。
在这里插入图片描述

再准备一个提供者

在父级项目cloud-alibaba-test中复制一份bill-7780,命名为bill-7781
在这里插入图片描述
引入bill-7781的pom文件
在这里插入图片描述

批量修改替换:

点击选中bill-7781项目 -> 点击上方的Edit -> 选中Find -> Replace in Files
进行替换
在这里插入图片描述
还有将bill-7780替换为为bill-7781,具体修改结合自身实际情况。

修改bootstrap.yml中配置的端口为7781,服务名与bill-7780中配置的保持一致

server:port: 7781
spring:profiles:active: devapplication:name: bill-7780 #与项目bill-7780的服务名保持一致# 注册服务cloud:nacos:discovery:server-addr: 127.0.0.1:8850 # nacos注册中心地址,可以配置多个username: nacospassword: nacosconfig:server-addr: 127.0.0.1:8850 # nacos配置中心地址file-extension: yamlgroup: DEFAULT_GROUP # 配置分组namespace: 935f0c39-db1c-4fc0-a997-35cd6f929740 # 命名空间ID

注意:将两个提供者(bill-7780和bill-7781)服务名改为一致端口号不一致,消费者(provider-7790)中调用服务(一个provider两个实例)

修改启动类

package com.lp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.lp.mapper")
public class Bill7781Application {public static void main(String[] args) {SpringApplication.run(Bill7781Application.class, args);}}

在这里插入图片描述

添加项目bill-7781到父级中,即在父级pom文件引入bill-7781模块

<modules><module>bill-7780</module><module>bill-7781</module><module>provider-7790</module><module>cloud-common</module>
</modules>

负载均衡轮询

在子项目provider-7790的pom文件中引入依赖

<!--客户端负载均衡loadbalancer-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

启动bill-7780项目、bill-7781项目和provider-7790项目
在这里插入图片描述
浏览器多次访问http://localhost:7790/bill/listByProId?id=1,会发现控制台中bill-7780和bill-7781的接口被依次调用(轮询)。

负载均衡随机

在项目provider-7790的config包中添加配置类RandomLoadBalancerConfig,实现随机策略

package com.lp.config;import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;public class RandomLoadBalancerConfig {@BeanReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactoryloadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}

在SmbmsBillService中配置注解

package com.lp.service.api;import com.lp.config.RandomLoadBalancerConfig;
import com.lp.service.api.impl.SmbmsBillServiceImpl;
import com.lp.utils.ResultAJAX;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(name = "bill-7780", path = "billApi", fallback = SmbmsBillServiceImpl.class) //name:为服务提供者的服务名
@LoadBalancerClient(name = "bill-7780", configuration = RandomLoadBalancerConfig.class)
public interface SmbmsBillService {@GetMapping("/listByProId")//要与BillServiceAPI类中的方法使用的请求方式一致,比如均为@GetMapping或@RequestMappingpublic ResultAJAX listByProId(@RequestParam("id") Integer id); //必须添加@RequestParam注解
}

重启provider-7790,浏览器多次访问http://localhost:7790/bill/listByProId?id=1,会发现随机调用bill-7780和bill-7781的接口。

http://www.dtcms.com/a/576871.html

相关文章:

  • 【微服务】(4) 负载均衡
  • 【Qt】Qt实践记录3——UDP通信
  • 考研408--计算机网络--day3--
  • 从云原生部署到智能时序分析:基于 Kubernetes 的 Apache IoTDB 集群实战与 TimechoDB 国产化增强特性深度解析
  • LLaVA-NeXT 学习笔记
  • 投资融资理财网站模板网站搭建福州公司
  • OpenStack创建实例一直处于创建且未分配IP问题解决
  • C++的诗行:一文掌握内存管理中 new/delete 接口正确调用与常见场景适配
  • 谷歌网站 百度做网站对服务器什么要求高
  • Smartproxy 企业级解决方案
  • 图像分类深度学习
  • 自监督骨干(DINOv2)用于内镜分割与跟踪的全面实现分析
  • 6.基础--SQL--DDL表操作-创建查询
  • 《算法闯关指南:优选算法--位运算》--34.判断字符是否唯一,35.丢失的数字
  • 四川建设网网站首页网站开发 周期
  • linux怎么检查磁盘是否有坏道
  • 微信小程序开发——第三章:WXML 与 WXSS —— 小程序页面结构与样式设计
  • Pytorch 内存布局优化:Contiguous Memory
  • pytorch-张量
  • MYSQL CDC 同步到 PAIMON
  • MATLAB实现高光谱分类算法
  • Linux:WSL常用指令总结
  • Git 最近提交中不小心包含了多余的文件怎么办
  • T100打破远程孤岛-轻松实现异地组网-P2P打洞+UDP NAT 穿透
  • 建设网站人员名单企业网站建设报价单
  • 联通研究院:基于‘多模态SCA+全周期协同’的中间件开源风险治理实践
  • 五子棋项目Alpha-Beta剪枝与MCTS+神经网络实现人机对弈算法对比报告
  • 测试题-5
  • 商洛免费做网站公司网站设计策划案
  • Java 项目 HTTP+WebSocket 统一权限控制实战