本站消息

站长简介/公众号


站长简介:逗比程序员,理工宅男,前每日优鲜python全栈开发工程师,利用周末时间开发出本站,欢迎关注我的微信公众号:幽默盒子,一个专注于搞笑,分享快乐的公众号

  价值13000svip视频教程,java大神匠心打造,零基础java开发工程师视频教程全套,基础+进阶+项目实战,包含课件和源码

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2021-05(14)

2021-06(54)

2021-07(10)

2021-08(60)

2021-09(21)

SpringCloud(2)Ribbon OpenFeign Hystrix 服务降级 熔断

发布于2021-05-29 19:34     阅读(293)     评论(0)     点赞(1)     收藏(1)


前言:本文会用到 前文SpringCloud(1)里面的微服务。

1、服务调用

1.1 Ribbon

1.1.1 简介

官网:https://github.com/Netflix/ribbon/wiki/Getting-Started

      Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。

     但是目前也进入维护模式,未来可能被Spring Cloud LoadBalacer替代

1.1.2 负载均衡LB(Load Balance)

    简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。

    常见的负载均衡有软件Nginx,LVS,硬件F5等。

1.1.3 Ribbon本地负载均衡客户端VS Nginx服务端负载均衡区别

复习:Nginx负载均衡 https://blog.csdn.net/chengqingshihuishui/article/details/116902124

(1)Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的。

(2)Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心上获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。

由上面的区别可以将负载均衡分为两种:集中式LB 与 进程内 LB

① 集中式LB

     即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方;

② 进程内 LB

    将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。

    Ribbon就是一个软负载均衡的客户端组件,就是负载均衡+RestTemplate调用,与Eureka结合的架构如下:

1.1.4 Ribbon的使用

(1)安装Ribbon

① 作为高级框架的附属品自动安装(比如Eureka)  

SpringCloud(1)第三节讲的Eureka就已经集成好了Ribbon

  1. <!--eureka client-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. </dependency>

这个starter里面有Ribbon依赖

② 单独安装Ribbon

  1. <dependency>
  2. <groupld>org.springframework.cloud</groupld>
  3. <artifactld>spring-cloud-starter-netflix-ribbon</artifactid>
  4. </dependency>

说明:在Web服务端项目里面,Ribbon肯定是集成在高级框架里面配套使用的。

(2)复习:RestTemplate

RestTemplate Java Doc

重点方法:

① getForObject() / getForEntity() - GET请求方法

      getForObject():返回对象为响应体中数据转化成的对象,基本上可以理解为Json。   

      getForEntity():返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等。

② postForObject() / postForEntity() - POST请求方法

    postForObject本质上是将对象放入HttpEntity中,然后将对象POST给一个url。直接形参放java对象也行,因为底层会完成java对象到HttpEntity 的自动转换。

     形参分别是传输的URL,传输的Object,和返回值的类型。这里返回类型是CommonResult<payment>,还记得前面专门在CommonResult实体类中写了一个只有两个参数的构造器吗

Exp:

  1. @GetMapping("/consumer/payment/getForEntity/{id}")
  2. public CommonResult<Payment> getPayment2(@PathVariable("id") Long id)
  3. {
  4. ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
  5. if(entity.getStatusCode().is2xxSuccessful()){
  6. return entity.getBody();//getForObject()
  7. }else{
  8. return new CommonResult<>(444,"操作失败");
  9. }
  10. }

 

1.1.5 Ribbon常用负载规则

Riboon使用 IRule 接口,根据特定算法从所有服务中,选择一个服务。而IRule 接口有7个实现类。每个实现类代表一个负载均衡算法:

① RoundRobinRule 轮询

② RandomRule 随机

③ RetryRule 先按照 轮询 的策略获取服务,如果获取服务失败则在指定时间内会进行重试

④ WeightedResponseTimeRule 对轮询的扩展,响应速度越快的实例选择权重越大,越容易被选择

⑤ BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务

⑥ AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例

⑦ ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器

1.1.6 Ribbon负载规则替换

  • 修改cloud-consumer-order80 子工程

(1)新建package - com.atguigu.myrule 

在com.atguigu.myrule下新建MySelfRule规则类

  1. @Configuration
  2. public class MySelfRule {
  3. @Bean
  4. public IRule myRule(){
  5. return new RandomRule();//随机负载均衡算法
  6. }
  7. }

特别注意:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类(负载均衡规则)就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。(也就是说不要将Ribbon配置类与主启动类同包)

修正:图片里的包应该是com.atguigu

小问题:既然都没扫描不到myrule这个包,你在组件上加了@Bean也没法添加进容器吧。那在这个包下的配置类myRule头上加@Bean注解还有什么意义呢,可不可以不加,毕竟都没扫描这个包了,难道加了@Bean注解还能进入spring容器吗

(2)在主启动类上加@RibbonClient注解,表示访问CLOUD-PAYMENT-SERVICE服务时,使用我们自定义的负载均衡算法

  1. @SpringBootApplication
  2. @EnableEurekaClient
  3. //添加到此处
  4. @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
  5. public class OrderMain80{
  6. public static void main( String[] args ){
  7. SpringApplication.run(OrderMain80.class, args);
  8. }
  9. }

 

1.2 OpenFeign

1.2.1 Feign简介

    Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

官网地址:https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign

Github地址:https://github.com/spring-cloud/spring-cloud-openfeign

1.2.2 Feign能干什么?

     Feign旨在使编写Java Http客户端变得更容易。

     前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。

(1)Feign集成了Ribbon

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

(2)Feign与OpenFeign

① Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。(已过期

② OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVc的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

特别说明:Feign已经停止维护,过期了。OpenFeign作为他的继承者,优化升级了Feign,后文说的Feign都是OpenFeign
 

1.2.3 OpenFeign的使用

接口+注解:微服务调用接口 + @FeignClient

(1)新建一个order子工程,用于feign测试,名为cloud-consumer-feign-order80

(2)改POM 

特别注意:openfeign依赖

  1. <parent>
  2. <artifactId>LearnCloud</artifactId>
  3. <groupId>com.atguigu.springcloud</groupId>
  4. <version>1.0.0-SNAPSHOT</version>
  5. </parent>
  6. <modelVersion>4.0.0</modelVersion>
  7. <artifactId>cloud-consumer-feign-order80</artifactId>
  8. <dependencies>
  9. <!--openfeign-->
  10. <dependency>
  11. <groupId>org.springframework.cloud</groupId>
  12. <artifactId>spring-cloud-starter-openfeign</artifactId>
  13. </dependency>
  14. <!--eureka client-->
  15. <dependency>
  16. <groupId>org.springframework.cloud</groupId>
  17. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  18. </dependency>
  19. <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
  20. <dependency>
  21. <groupId>com.lun.springcloud</groupId>
  22. <artifactId>cloud-api-commons</artifactId>
  23. <version>${project.version}</version>
  24. </dependency>
  25. <!--web-->
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-actuator</artifactId>
  33. </dependency>
  34. <!--一般基础通用配置-->
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-devtools</artifactId>
  38. <scope>runtime</scope>
  39. <optional>true</optional>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.projectlombok</groupId>
  43. <artifactId>lombok</artifactId>
  44. <optional>true</optional>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.springframework.boot</groupId>
  48. <artifactId>spring-boot-starter-test</artifactId>
  49. <scope>test</scope>
  50. </dependency>
  51. </dependencies>
  52. </project>

(3)改YML

  1. server:
  2. port: 80
  3. eureka:
  4. client:
  5. register-with-eureka: false
  6. service-url:
  7. defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

(4)主启动类

  1. @SpringBootApplication
  2. @EnableFeignClients //开启feign
  3. public class OrderFeignMain80 {
  4. public static void main(String[] args) {
  5. SpringApplication.run(OrderFeignMain80.class, args);
  6. }
  7. }

(5)业务类 

① Service接口

新建 项目\cloud-consumer-feign-order80(Module)\src\main\java\com\atguigu\springcloud\service 包

编写PaymentFeignService.java接口并新增注解@FeignClient

业务逻辑接口+@FeignClient配置(consumer调用provider服务)

  1. @Component
  2. @FeignClient(value = "CLOUD-PAYMENT-SERVICE")
  3. public interface PaymentFeignService{
  4. @GetMapping(value = "/payment/get/{id}")
  5. public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
  6. }

备注:去CLOUD-PAYMENT-SERVICE 所在的工程(负载均衡会选择去哪个具体工程调用实现类)找该调用该接口的实现类(Provider)

Feign自带负载均衡配置项

② Controller

  1. package com.atguigu.springcloud.controller;
  2. @RestController
  3. @Slf4j
  4. @RequestMapping("/consumer")
  5. public class OrderFeginController {
  6. @Resource
  7. private PaymentService paymentService;
  8. @GetMapping("/payment/get/{id}")
  9. public CommonResult<Payment> getPyamentById(@PathVariable("id")Long id){
  10. return paymentService.getPaymentById(id);
  11. }
  12. }

(6)测试

先启动2个eureka集群7001/7002

再启动2个微服务8001/8002

启动OpenFeign启动

http://localhost/consumer/payment/get/1

Feign自带负载均衡配置项

1.2.4 OpenFeign超时机制

OpenFeign 默认等待时间是1秒,超过1秒Provider没得反应,就会直接报错,如下图:

设置超时时间,修改配置文件

  1. #设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒)
  2. ribbon:
  3. #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  4. ReadTimeout: 5000
  5. #指的是建立连接后从服务器读取到可用资源所用的时间
  6. ConnectTimeout: 5000

1.2.5 OpenFeign日志增强

(1)日志打印功能(配置好以后,自动打印)

        Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign 中 Http请求的细节。

        说白了就是对Feign接口的调用情况进行监控和输出

(2)日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

(3)用spring注解创建日志Bean

  1. @Configuration
  2. public class FeignConfig
  3. {
  4. @Bean
  5. Logger.Level feignLoggerLevel()
  6. {
  7. return Logger.Level.FULL; //日志级别
  8. }
  9. }

(4)YML文件里需要开启日志的Feign客户端

  1. logging:
  2. level:
  3. # feign日志以什么级别监控哪个接口
  4. com.atguigu.springcloud.service.PaymentFeignService: debug

(5)启动微服务即可

2、 服务降级

2.1 服务雪崩

① 分布式系统面临的问题

    复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。

② 服务雪崩

      多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.

    对于高流量的应用来说,单一的后避依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。

    当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

2.2 Hystrix

2.2.1 简介

        Hystrix是一个用于处理分布式系统的延迟容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

        "断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

  • 主要作用

① 服务降级:比如当某个服务繁忙,不能让客户端的请求一直等待,应该立刻返回给客户端一个备选方案。

② 服务熔断:当某个服务出现问题,卡死了,不能让用户一直等待,需要关闭所有对此服务的访问然后调用服务降级。

③ 服务限流:比如秒杀场景,不能访问用户瞬间都访问服务器,限制一次只可以有多少请求。

④ 接近实时的监控

2.2.2 服务降级
 

 

原文链接:https://blog.csdn.net/chengqingshihuishui/article/details/117340311



所属网站分类: 技术文章 > 博客

作者:我是不是很美

链接:http://www.javaheidong.com/blog/article/207099/1bb388f6e85d851c980c/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

1 0
收藏该文
已收藏

评论内容:(最多支持255个字符)