Day97.SpringCloud:概述、Eureka(注册发现)、Ribbon(负载均衡与调用)、OpenFeign(远程调用)

目录

一、微服务、分布式概念

分布式思想与基本概念 

二、SpringCloud 概述

三、SpringCloud 微服务环境搭建 (RestTemplate应用)

1、服务提供者 (8001) 复制粘贴即可。

2、服务消费者 (80) 

RestTemplate

Hutool工具包

postman 模拟发起请求 

热部署Devtools 

四、Eureka:服务注册与发现

1、IDEA生成eurekaServer端服务注册中心 (7001)

2、服务提供者8001 注册到7001

3、服务消费者 注册到7001

五、Ribbon:负载均衡服务调用  ★

如何替换策略?

六、OpenFeign:服务接口远程调用  ★

Ribbon 超时设置

OpenFeign 日志打印功能


  • 微服务、分布式概念、微服务架构 
  • 注册中心:Eureka
  • 负载均衡:Ribbon
  • 声明式调用远程方法:OpenFeign
  • 熔断、降级、监控:Hystrix
  • 网关:Gateway
  • 链路跟踪:Sleuth 
  • 服务注册和配置中心:Spring Cloud Alibaba Nacos
  • 熔断、降级、限流:Spring Cloud Alibaba Sentinel

一、微服务、分布式概念

Day85.Dubbo分布式RPC框架、Zookeeper、provider | consumer 开发、管理控制台、事物问题_焰火青年·的博客-CSDN博客

https://www.martinfowler.com/articles/microservices.html 微服务microservices

微服务|YYGCui's blog

什么是微服务?

简单来说,微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级(restful风格)通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。

总结:

1. 微服务需要根据业务模块拆分,做到单一职责,不要重复开发相同
务。

2. 微服务可以将业务暴露为接口,供其它微服务使用

3. 不同微服务都应该有自己独立的数据库

分布式服务架构

分布式一定是集群的(防止单点故障)。 而集群并不一定就是分布式的

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键

RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。

它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。

 

分布式思想与基本概念 

高并发 

通过设计保证系统可以并行处理很多请求。应对大量流量请求

Tomcat最多支持并发多少用户?

Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。

当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群

具体能承载多少并发,需要看硬件的配置,CPU 越多性能越高,分配给 JVM 的内存越多性能也就越高,但也会加重 GC 的负担。

操作系统对于进程中的线程数有一定的限制:

Windows 每个进程中的线程数不允许超过 2000

Linux 每个进程中的线程数不允许超过 1000

另外,在 Java 中每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用。

Tomcat 默认的 HTTP 实现是采用阻塞式的 Socket 通信,每个请求都需要创建一个线程处理。这种模式下的并发量受到线程数的限制,但对于 Tomcat 来说几乎没有 BUG 存在了。

Tomcat 还可以配置 NIO 方式的 Socket 通信,在性能上高于阻塞式的,每个请求也不需要创建一个线程进行处理,并发能力比前者高。但没有阻塞式的成熟。

这个并发能力还与应用的逻辑密切相关,如果逻辑很复杂需要大量的计算,那并发能力势必会下降。如果每个请求都含有很多的数据库操作,那么对于数据库的性能也是非常高的。

对于单台数据库服务器来说,允许客户端的连接数量是有限制的。

并发能力问题涉及整个系统架构和业务逻辑。

系统环境不同,Tomcat版本不同、JDK版本不同、以及修改的设定参数不同。并发量的差异还是满大的。

  • maxThreads="1000" 最大并发数 ,默认值为200
  • minSpareThreads="100"//初始化时创建的线程数,默认值为10
  • acceptCount="700"// 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理,默认值为100

Apache Tomcat 8 Configuration Reference (8.0.53) - The HTTP Connector

高并发衡量指标 

  • 响应时间(RT)
    • 请求做出响应的时间,即一个http请求返回所用的时间
  • 吞吐量
    • 系统在单位时间内处理请求的数量
  • QPS(Query/Request Per Second)、 TPS(Transaction Per Second)
  • 每秒查询(请求)数、每秒事务数
    • 专业的测试工具:Load Runner
    • Apache ab
    • Apache JMeter
  • 并发用户数
    • 承载的正常使用系统功能的用户的数量

高可用

服务集群部署

数据库主从+双机热备

  • 主-备方式(Active-Standby方式)

主-备方式即指的是一台服务器处于某种业务的激活状态(即Active状态),另一台服务器处于该业务的备用状态(即Standby状态)。

  • 双主机方式(Active-Active方式)

双主机方式即指两种不同业务分别在两台服务器上互为主备状态(即Active-Standby和Standby-Active状态)

注册中心 

保存某个服务所在地址等信息,方便调用者实时获取其他服务信息

提供者和消费者是相对而言的

  • 服务注册:服务提供者
  • 服务发现:服务消费者

负载均衡 

动态将请求派发给比较闲的服务器

策略:

  1. 轮询(Round Robin)
  2. 加权轮询(Weighted Round Robin)
  3. 随机Random
  4. 哈希Hash
  5. 最小连接数LC
  6. 最短响应时间LRT

服务雪崩 

服务之间复杂调用,一个服务不可用,导致整个系统受影响不可用

限流

限制某个服务每秒的调用本服务的频率

API网关

API网关要做很多工作,它作为一个系统的后端总入口,承载着所有服务的组合路由转换等工作,除此之外,我们一般也会把安全,限流,缓存,日志,监控,重试,熔断等放到 API 网关来做。

服务跟踪 

追踪服务的调用链,记录整个系统执行请求过程。如:请求响应时间,判断链中的哪些服务属于慢服务(可能存在问题,需要改善)

弹性云

Elastic Compute Service(ECS)弹性计算服务

动态扩容,压榨服务器闲时能力

例如:双11,618,高峰时多配置些服务器,平时减少多余的服务器配置(用于其他服务应用),避免资源浪费

二、SpringCloud 概述

SpringCloud 是微服务一站式服务解决方案,微服务全家桶。它是微服务开发的主流技术栈。它采用了名称,而非数字版本号。

springCloud 和 springCloud Alibaba 目前是最主流的微服务框架组合。

 SpringCloud版本选择

选用 springboot 和 springCloud 版本有约束,不按照它的约束会有冲突。

官方版本的对应信息:https://start.spring.io/actuator/info

SpringBoot2.3.6版和SpringCloud Hoxton.SR9版

SpringCloud Alibaba 2.2.6

三、SpringCloud 微服务环境搭建 (RestTemplate应用)

与springboot搭建基本相同 服务提供者(cloud-provider-payment8001)服务消费者(cloud-consumer-order80)

  1. 建module
  2. 改POM 添加依赖
  3. 写YML
  4. 主启动
  5. 业务类 (orm - dao - service - controller)

父工程xml

    com.atguigu.springcloudspringcloud1.0-SNAPSHOTpomUTF-81.81.84.121.2.171.16.188.0.261.1.161.3.0org.springframework.bootspring-boot-dependencies2.3.6.RELEASEpomimportorg.springframework.cloudspring-cloud-dependenciesHoxton.SR9pomimportcom.alibaba.cloudspring-cloud-alibaba-dependencies2.2.6.RELEASEpomimportmysqlmysql-connector-java${mysql.version}com.alibabadruid${druid.version}org.mybatis.spring.bootmybatis-spring-boot-starter${mybatis.spring.boot.version}junitjunit${junit.version}log4jlog4j${log4j.version}org.projectlomboklombok${lombok.version}trueorg.springframework.bootspring-boot-maven-plugintruetrue

1、服务提供者 (8001) 复制粘贴即可。

1. 创建项目cloud-provider-payment8001,引入依赖

org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.mybatis.spring.bootmybatis-spring-boot-startercom.alibabadruid-spring-boot-starter1.1.10mysqlmysql-connector-javaorg.springframework.bootspring-boot-starter-jdbcorg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtest

2. YML配置文件

server:port: 8001spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/cloud2022?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: rootpassword: *******mybatis:mapperLocations: classpath:/mapper/*.xmltype-aliases-package: com.atguigu.springcloud.entities

3. 主启动类

package com.atguigu.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan(basePackages = "com.atguigu.springcloud.dao") //扫描dao包,创建代理对象
@SpringBootApplication
public class PaymentMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentMain8001.class,args);}
}

 4. 业务类

数据库表

主实体Payment

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {private Long id;private String serial;
}

Json封装体CommonResult

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult  implements Serializable{private Integer code;private String message;private T data;public CommonResult(Integer code,String message){this(code,message,null);//如果这行报错,请安装lombok插件}
}

接口PaymentDao

@Component       //代替@Repository声明bean
@Mapper               //mybatis提供的,等价:@MapperScan("com.atguigu.springcloud.dao")
//@Repository     //spring提供的。在此,只是为了声明bean对象
public interface PaymentDao {public int create(Payment payment);    public Payment getPaymentById(@Param("id") Long id);
}

映射


insert into payment(serial) values(#{serial});

Service 接口与实现

public interface PaymentService {public int create(Payment payment); //写public Payment getPaymentById(Long id);  //读取
}@Service
@Transactional
public class PaymentServiceImpl implements PaymentService {@AutowiredPaymentDao paymentDao;@Overridepublic int create(Payment payment) {return paymentDao.create(payment);}@Overridepublic Payment getPaymentById(Long id) {return paymentDao.getPaymentById(id);}
}

Controller

@RestController
@Slf4j
public class PaymentController {@Resourceprivate PaymentService paymentService;@PostMapping(value = "/payment/create")public CommonResult create(Payment payment){ //埋雷int result = paymentService.create(payment);log.info("*****插入结果:"+result);if (result>0){  //成功return new CommonResult(200,"插入数据库成功",result);}else {return new CommonResult(444,"插入数据库失败",null);}}@GetMapping(value = "/payment/get/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.getPaymentById(id);log.info("*****查询结果:"+payment);if (payment!=null){  //说明有数据,能查询成功return new CommonResult(200,"查询成功",payment);}else {return new CommonResult(444,"没有对应记录,查询ID:"+id,null);}}
}

2、服务消费者 (80

1. 创建项目cloud-consumer-order80,引入依赖

    org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.mybatis.spring.bootmybatis-spring-boot-startercom.alibabadruid-spring-boot-starter1.1.10mysqlmysql-connector-javaorg.springframework.bootspring-boot-starter-jdbcorg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtest

2. YML文件

server:port: 80
spring:application:name: cloud-consumer-order80

3. 主启动 

@SpringBootApplication
//@EnableEurekaClient//声明当前应用80为Eureka(7001)的客户端
//在哪个请求上,采用哪种规则
//@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}

4. 业务类 

创建entities
(将cloud-provider-payment8001工程下的entities包下的两个实体类复制过来)

RestTemplate

由于没有引入OpenFeign,所以暂时使用RestTemplate 类远程调用

RestTemplate提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问Restful服务模板类,是Spring 提供的用于访问Rest服务的客户端模板工具集

官网地址: RestTemplate (Spring Framework 5.2.2.RELEASE API)

使用RestTemplate访问Restful接口非常的简单粗暴无脑。(url,requestMap,ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、Http响应转换被转换成的对象类型

缺点:面向模板类编程,不是面向接口编程

config配置类

@SpringBootConfiguration//声明一个配置类
public class ApplicationContextConfig {//重点 模板类//@RestTemplate 只能进行远程调用@Bean//@LoadBalanced //RestTemplate + Ribbon 实现远程调用和负载均衡(轮询)public RestTemplate restTemplate(){return new RestTemplate();}
}

创建controller 

@RestController
public class OrderController {//基于 RestTemplate 模板类进行远程调用@AutowiredRestTemplate restTemplate;public static final String PATH = "http://localhost:8001";@RequestMapping("/consumer/payment/get/{id}")public CommonResult get(@PathVariable("id") Long id){CommonResult commonResult = restTemplate.getForObject(PATH + "/payment/get/" + id, CommonResult.class);System.out.println("commonResult = " + commonResult);return commonResult;}@RequestMapping("/consumer/payment/create")public CommonResult create(@RequestBody Payment payment) {System.out.println("payment = " + payment);CommonResult commonResult = restTemplate.postForObject(PATH + "/payment/create", payment, CommonResult.class);return commonResult;}/*  //面向接口编程:推荐 使用OpenFeign组件@AutowiredPaymentService paymentService; //注入代理对象@RequestMapping("/consumer/payment/get/{id}")public CommonResult get(@PathVariable("id") Long id){Payment payment = paymentService.getPaymentById(id);System.out.println("payment = " + payment);return new CommonResult(200,"操作成功",payment);}@RequestMapping("/consumer/payment/create")public CommonResult create(@RequestBody Payment payment){System.out.println("payment = " + payment);paymentService.create(payment);return new CommonResult(200,"操作成功");}*/}

​​​​

测试

  1. 先启动cloud-provider-payment8001
  2. 再启动cloud-consumer-order80
  3. http://localhost/consumer/payment/get/32
  4. 不要忘记@RequestBody注解
  5. 服务提供者接口方法需要增加@RequestBody注解(踩雷or破雷);否则,接收不到数据。

Hutool工具包

封装实体类代码 (在弄一个工具项目,通过Maven继承传递。略)

糊涂工具包:Hutool — 🍬A set of tools that keep Java sweet.

        cn.hutoolhutool-all5.1.0

postman 模拟发起请求 

热部署Devtools 

1. 子工程添加依赖、插件

org.springframework.bootspring-boot-devtoolsruntimetrue

 2. 父工程添加插件


下一段配置黏贴到父工程当中的pom里
org.springframework.bootspring-boot-maven-plugintruetrue

3. Enabling automatic build

4. Ctrl+Shift+Alt+/选择Registry…,重启idea

compiler.automake.allow.when.app.running -> 自动编译

compile.document.save.trigger.delay -> 自动更新文件;它主要是针对静态文件如JS CSS的更新,将延迟时间减少后,直接按F5刷新页面就能看到效果!

 热部署:2021idea找不到 Registry中没有找到compiler.automake.allow.when.app.running选项

四、Eureka:服务注册与发现

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理。

在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂、所以需要进行服务治理,管理服务与服务之间依赖关联,以实现服务调用,负载均衡、容错等,实现服务发现与注册

 Eureka Client通过注册中心进行访问

是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、默认使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会在Eureka Server发送心跳(默认周期30秒zookeeper为10秒)。如果Eureka Server在多个心跳周期内没有收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移出(默认90秒

Eureka两组件

  • Eureka Server提供服务注册服务

各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

  • Eureka Client通过注册中心进行访问

是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会在Eureka Server发送心跳(默认周期30秒)。如果Eureka Server在多个心跳周期内没有收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移出(默认90秒

1、IDEA生成eurekaServer端服务注册中心 (7001)

1.新建项目 cloud-eureka-server7001,导入依赖

    org.springframework.cloudspring-cloud-starter-netflix-eureka-servercom.atguigu.springcloudcloud-api-commons${project.version}org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklombokorg.springframework.bootspring-boot-starter-testtestjunitjunit

2. 配置application.yml 文件

server:port: 7001eureka:instance:hostname: localhostclient:register-with-eureka: falsefetchRegistry: falseservice-url:defaultZone: http://localhost:7001/eureka

3. 启动类,添加@EnableEurekaServer注解

@SpringBootApplication
@EnableEurekaServer //声明当前应用为Eureka服务器端
public class App {public static void main(String[] args) {SpringApplication.run(App.class,args);}

4. 测试访问 http://localhost:7001/ 

2、服务提供者8001 注册到7001

1. 修改项目 cloud-provider-payment8001,导入依赖

        org.springframework.cloudspring-cloud-starter-netflix-eureka-client

2. 修改 YML配置文件

#8001 向 7001进行注册
eureka:client:register-with-eureka: truefetchRegistry: trueservice-url:defaultZone: http://localhost:7001/eureka

3.主启动 加入@EnableEurekaClient注解

@SpringBootApplication
@MapperScan(basePackages = "com.atguigu.springcloud.dao") //扫描dao包,创建代理对象
@EnableEurekaClient //声明当前应用8001为Eureka(7001)的客户端
public class PaymentMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentMain8001.class,args);}
}

3、服务消费者 注册到7001

1. 新建Module:cloud-consumer-order80,导入依赖

        org.springframework.cloudspring-cloud-starter-netflix-eureka-client

2. 添加YML配置文件

eureka:client:register-with-eureka: truefetchRegistry: trueservice-url:defaultZone: http://localhost:7001/eureka

3.主启动类 加入@EnableEurekaClient注解

@SpringBootApplication
@EnableEurekaClient//声明当前应用80为Eureka(7001)的客户端
//在哪个请求上,采用哪种规则(ribbon)
//@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}}

测试 

http://localhost/consumer/payment/get/31

测试8001服务和80服务效果一样

五、Ribbon:负载均衡服务调用  ★

Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用

Ribbon客户端组件提供一系列完善的配置项,如:连接超时,重试等。

简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。

Ribbon目前也进入维护模式,未来替换方案: Spring Cloud LoadBalancer

注:Feign、Nacos 默认集成了 Ribbon

  • Ribbon的本地负载均衡客户端  VS Nginx服务端负载均衡区别
    • Nginx是服务器负载均衡,客户端所有请求都会交给Nginx,然后,由nginx实现转发请求。即负载均衡是由服务器端完成的。
    • Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用。
  • 集中式LB
    • 即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如Nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;
  • 进程内LB
    • ​​​​​将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
    • Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
  • Ribbon=负载均衡+RestTemplate调用

1. 引入依赖

        

2. 服务消费者80 配置类中 模板对象加入注解 @LoadBalanced

@SpringBootConfiguration//声明一个配置类
public class ApplicationContextConfig {//重点 模板类//RestTemplate 只能进行远程调用@Bean@LoadBalanced //RestTemplate + Ribbon 实现远程调用和负载均衡(轮询)public RestTemplate restTemplate(){return new RestTemplate();}
}

3. 修改地址

    //public static final String PATH = "http://localhost:8001";//修改接收请求地址: 从7001订阅服务,获取三个实例 public static final String PATH = "http://CLOUD-PAYMENT-SERVICE";@RequestMapping("/consumer/payment/get/{id}")public CommonResult get(@PathVariable("id") Long id){CommonResult commonResult = restTemplate.getForObject(PATH + "/payment/get/" + id, CommonResult.class);System.out.println("commonResult = " + commonResult);return commonResult;}

4. 构建支付服务提供者集群环境

启动三个服务,设置不同端口。测试轮询效果

如何替换策略?

Ribbon 底层使用了 Irule 接口,实现各种负载均衡策略

IRule:根据特定算法从服务列表中选取一个要访问的服务

  1. com.netflix.loadbalancer.RoundRobinRule 轮询,默认策略。
  2. com.netflix.loadbalancer.RandomRule  随机
  3. com.netflix.loadbalancer.RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
  4. WeightedResponseTimeRule  对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
  5. BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  6. AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例
  7. ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化订制的目的了。

1. 在启动类上一级新建MySelfRule规则类

@Configuration
public class MySelfRule {@Beanpublic IRule myRule(){return new RandomRule();//定义为随机}
}

2. 主启动类添加@RibbonClient

@SpringBootApplication
@EnableEurekaClient//声明当前应用80为Eureka(7001)的客户端
//在哪个请求上,采用哪种规则
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}

六、OpenFeign:服务接口远程调用  ★

Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。(上面的例子使用了RestTemplate)

SpringCloud 对Feign 进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign 可以与 Eureka Ribbon 组合使用以支持 负载均衡

接口定义:狭义:interface声明的类  广义:对外暴露的类、方法也可称为接口

Feign 集成了 Ribbon

利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

Feign和OpenFeign两者区别

使用方式:微服务调用接口+@FeignClient

1. 新建Module:cloud-consumer-feign-order80,导入依赖

org.springframework.cloudspring-cloud-starter-openfeignorg.springframework.cloudspring-cloud-starter-netflix-eureka-clientcom.atguigu.springcloudcloud-api-commons${project.version}org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-actuatororg.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtest

2. YML文件

server:port: 80
spring:application:name: cloud-consumer-feign-order80
eureka:client:register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://localhost:7001/eureka

3. 主启动类 添加注解@EnableFeignClients

@SpringBootApplication
@EnableEurekaClient //声明当前应用80为Eureka(7001)的客户端
@EnableFeignClients //启用OpenFeign组件远程调用功能
public class App {public static void main(String[] args) {SpringApplication.run(App.class);}
}

4. 业务层 创建接口并新增注解  @FeignClient

//远程调用接口:
@Component //声明bean对象,创建代理对象,进行远程调用
@FeignClient("CLOUD-PAYMENT-SERVICE") //指定调用微服务的名称
public interface PaymentFeignService {//接口方法声明要求:需要与被调用的服务的controller方法声明保持一致@GetMapping(value = "/payment/get/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id);@PostMapping(value = "/payment/create")public CommonResult create(@RequestBody Payment payment);
}

4. 控制层Controller

@RestController
public class OrderFeignController {//远程调用微服务接口(默认集成Ribbon 轮询),实现原原理: 代理@AutowiredPaymentFeignService paymentFeignService; @RequestMapping("/consumer/payment/get/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id){CommonResult commonResult = paymentFeignService.getPaymentById(id);return commonResult;}}

5. 测试

Ribbon 超时设置

OpenFeign远程调用 默认一秒超时,有时候我们需要设置Feign客户端的超时控制,即Ribbon的超时时间,因为Feign集成了Ribbon进行负载均衡

如果不配置ribbon的重试次数,默认会重试一次

注意:

默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试

非GET方式请求,只有连接异常时,才会进行重试

如果对增删改进行重试,应通过乐观锁机制,进行幂等处理,防止重复提交

1、修改yml配置文件

ribbon:ReadTimeout:  3000ConnectTimeout: 3000MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用OkToRetryOnAllOperations: false #是否所有操作都重试(false时只对get重试)#hystrix(降级熔断)的超时时间
hystrix:command:default:execution:timeout:enabled: trueisolation:thread:timeoutInMilliseconds: 9000

一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制)

OpenFeign 日志打印功能

日志级别

NONE:默认的,不显示任何日志

BASIC:仅记录请求方法、RUL、响应状态码及执行时间

HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息

FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据

1. 配置类,配置日志bean,指定日志级别

@Configuration //用哪个都可以,一个SpringBoot提供,一个spring提供
//@SpringBootConfiguration
public class FeignConfig {@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}}

级别: 

2. YML配置需要开启日志的Feign客户端 

logging:level:com.atguigu.springcloud.service.PaymentFeignService: debug


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部