SpringCloud——Ribbon的使用、Hystrix熔断器的使用

目录

五、负载均衡 Spring Cloud Ribbon

跳转到目录

5.1 Ribbon 简介

解决了集群服务中,多个服务高效率访问的问题。

什么是Ribbon?

Ribbon是Netflix发布的负载均衡器,有助于控制HTTP客户端行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于负载均衡算法,自动帮助服务消费者请求。

Ribbon默认提供的负载均衡算法:轮询,随机其他…。当然,我们可用自己定义负载均衡算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eNQ26YdG-1588154558601)(02-SpringCloud-讲义.assets/1564761498131.png)]

5.2 入门案例

实现负载均衡访问用户服务

如果想要做负载均衡,我们的服务至少2个以上。所有第一步目标

实现步骤:

第一步:启动两个user_service服务

  1. 修改配置文件端口获取方式
  2. 编辑应用启动配置
  3. 启动两个提供者服务
  4. 在注册中心查询是否启动成功

第二步:开启消费者负载均衡

  1. 在RestTemplate的注入方法上加入@LoadBalanced注解
  2. 修改调用请求的Url地址,改为服务名称调用
  3. 访问页面查看效果

实现过程:

第一步:启动两个user_service应用

  1. 修改UserServiceApplication的application.yml配置文件

    • 端口9091改为,${port:9091}
      在这里插入图片描述
  2. 编辑应用启动配置
    在这里插入图片描述

  3. 复制一份UserServiceApplication
    在这里插入图片描述

  4. 启动两个UserServiceApplication应用

  5. Eureka服务中心可查看,注册成功
    在这里插入图片描述

第二步:开启消费者调用负载均衡

Eureka已经集成Ribbon,所以无需引入依赖。

  1. 在RestTemplate的配置方法上添加@LoadBalanced注解即可

    @Bean
    @LoadBalanced//开启负载均衡
    public RestTemplate restTemplate(){
          
          
        return new RestTemplate();
    }
    
    
  2. 修改ConsumerController调用方式,不再手动获取ip和端口,而是直接通过服务名称调用

    @GetMapping("{id}")
    public User queryById(@PathVariable Long id){
          
          
        String url = String.format("http://user-service/user/%d", id);
        return restTemplate.getForObject(url,User.class);
    }
    
    
  3. 访问页面查看结果;并在9091和9092的控制台查看执行情况

配置修改轮询策略:Ribbon默认的负载均衡策略是轮询,通过如下

# 修改服务地址轮询策略,默认是轮询,配置之后变随机
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

SpringBoot可以修改负载均衡规则,配置为ribbon.NFLoadBalancerRuleClassName

格式{服务提供者名称}.ribbon.NFLoadBalancerRuleClassName

六、熔断器 Spring Cloud Hystrix

跳转到目录

6.1 Hystrix 简介

在这里插入图片描述

Hystrix,英文意思是豪猪,全身是刺,刺是一种保护机制。Hystrix也是Netflix公司的一款组件。

Hystrix的作用是什么?

Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库、防止出现级联失败也就是雪崩效应。

在这里插入图片描述

6.2 雪崩效应

  • 微服务中,一个请求可能需要多个微服务接口才能实现,会形成复杂的调用链路。
  • 如果某服务出现异常,请求阻塞,用户得不到响应,容器中线程不会释放,于是越来越多用户请求堆积,越来越多线程阻塞。
  • 单服务器支持线程和并发数有限,请求如果一直阻塞,会导致服务器资源耗尽,从而导致所有其他服务都不可用,从而形成雪崩效应;

Hystrix解决雪崩问题的手段,主要是服务降级**(兜底)**,线程隔离;

6.3 熔断案例

**目标:服务提供者的服务出现了故障,服务消费者快速失败给用户友好提示。体验服务降级 **

实现步骤:

  1. 引入熔断的依赖坐标
  2. 开启熔断的注解
  3. 编写服务降级处理的方法
  4. 配置熔断的策略
  5. 模拟异常代码
  6. 测试熔断服务效果

实现过程:

  1. 引入熔断的依赖坐标:

    • consumer_service中加入依赖
    <!--熔断Hystrix starter-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
    
  2. 开启熔断的注解

    //注解简化写法:微服务中,注解往往引入多个,简化注解可以使用组合注解。@SpringCloudApplication =等同于@SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker
    @SpringBootApplication
    @EnableDiscoveryClient//开启服务发现
    @EnableCircuitBreaker//开启熔断
    public class ConsumerApplication {
          
          
        @Bean
        @LoadBalanced//开启负载均衡
        public RestTemplate restTemplate(){
          
          
            return new RestTemplate();
        }
        public static void main(String[] args) {
          
          
            SpringApplication.run(ConsumerApplication.class,args);
        }
    }
    
    
  3. 编写服务降级处理方法:使用@HystrixCommand定义fallback方法。

    @RequestMapping("{id}")
    @HystrixCommand(fallbackMethod ="
                    ")
    public String queryById(@PathVariable Long id){
          
          
        String url = String.format("http://user-service/user/%d", id);
        return restTemplate.getForObject(url,String.class);
    }
    
    public String queryByIdFallback(Long id){
          
          
        return "对不起,网络太拥挤了!";
    }
    
    
  4. 配置熔断策略

    1. 常见熔断策略配置
    2. 熔断后休眠时间:sleepWindowInMilliseconds
    3. 熔断触发最小请求次数:requestVolumeThreshold
    4. 熔断触发错误比例阈值:errorThresholdPercentage
    5. 熔断超时时间:timeoutInMilliseconds
    # 配置熔断策略:
    hystrix:
      command:
        default:
          circuitBreaker:
          	# 原理分析中解释配置含义
            # 强制打开熔断器 默认false关闭的。测试配置是否生效
            forceOpen: false
            # 触发熔断错误比例阈值,默认值50%
            errorThresholdPercentage: 50
            # 熔断后休眠时长,默认值5秒
            sleepWindowInMilliseconds: 5000
            # 熔断触发最小请求次数,默认值是20
            requestVolumeThreshold: 10
          execution:
            isolation:
              thread:
                # 熔断超时设置,默认为1秒
                timeoutInMilliseconds: 2000
    
    
  5. 模拟异常代码

    @GetMapping("{id}")
    @HystrixCommand(fallbackMethod ="queryByIdFallback")
    public String queryById(@PathVariable Long id){
          
          
        //如果参数为1抛出异常,否则 执行REST请求返回user对象
        if (id == 1){
          
          
            throw new RuntimeException("too busy!!!");
        }
        String url = String.format("http://user-service/user/%d", id);
        return restTemplate.getForObject(url,String.class);
    }
    
    
  6. 测试熔断的情况(模拟请求超时):

    1. 访问超时:服务提供者线程休眠超过2秒,访问消费者触发fallback方法。
    @Service
    public class UserService {
          
          
        @Autowired
        private UserMapper userMapper;
        
        public User queryById(Long id){
          
          
            try {
          
          
                Thread.sleep(2000);
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
            return userMapper.selectByPrimaryKey(id);
        }
    }
    
    
    1. 服务不可用:停止user-service服务提供者。访问消费者触发fallback方法。

在这里插入图片描述

6.4 熔断原理分析

熔断器的原理很简单,如同电力过载保护器。

熔断器状态机有3个状态:

  • 关闭状态,所有请求正常访问
  • 打开状态,所有请求都会被降级。
    • Hystrix会对请求情况计数,当一定时间失败请求百分比达到阈值,则触发熔断,断路器完全关闭
    • 默认失败比例的阈值是50%,请求次数最低不少于20次
  • 半开状态
    • 打开状态不是永久的,打开一会后会进入休眠时间(默认5秒)。休眠时间过后会进入半开状态。
    • 半开状态:熔断器会判断下一次请求的返回状况,如果成功,熔断器切回关闭状态。如果失败,熔断器切回打开状态。
      在这里插入图片描述

熔断器的核心解决方案:线程隔离和服务降级。

  • 线程隔离。
  • 服务降级(兜底方法)。

线程隔离和服务降级之后,用户请求故障时,线程不会被阻塞,更不会无休止等待或者看到系统奔溃,至少可以看到执行结果(熔断机制)。

什么时候熔断:

  1. 访问超时
  2. 服务不可用(死了)
  3. 服务抛出异常(虽然有异常但还活着)
  4. 其他请求导致服务异常到达阈值,所有服务都会被降级

模拟异常测试:http://localhost:8080/consumer/1失败请求发送10次以上。再请求成功地址http://localhost:8080/consumer/2,发现服务被熔断,会触发消费者fallback方法。

6.5 扩展-服务降级的fallback方法:

两种编写方式:编写在类上,编写在方法上。在类的上边对类的所有方法都生效。在方法上,仅对当前方法有效。

  1. 方法上服务降级的fallback兜底方法

    • 使用HystrixCommon注解,定义
    • @HystrixCommand(fallbackMethod=“queryByIdFallBack”)用来声明一个降级逻辑的fallback兜底方法
  2. 类上默认服务降级的fallback兜底方法

    • 刚才把fallback写在了某个业务方法上,如果方法很多,可以将FallBack配置加在类上,实现默认FallBack

    • @DefaultProperties(defaultFallback=”defaultFallBack“),在类上,指明统一的失败降级方法;

    • @RestController
      @RequestMapping("/consumer")
      @DefaultProperties(defaultFallback = "defaultFallback")//开启默认的FallBack,统一失败降级方法(兜底)
      public class ConsumerController {
              
              
          @GetMapping("{id}")
          @HystrixCommand
          public String queryById(@PathVariable Long id){
              
              
              //如果参数为1抛出异常,否则 执行REST请求返回user对象
              if (id == 1){
              
              
                  throw new RuntimeException("too busy!!!");
              }
              String url = String.format("http://user-service/user/%d", id);
              return restTemplate.getForObject(url,String.class);
          }
      	/**
      	 * queryById的降级方法
      	 */
          public String queryByIdFallback(Long id){
              
              
         return "对不起,网络太拥挤了!";
          }
          /**
      	 * 默认降级方法
      	 */
          public String defaultFallback(){
              
              
              return "默认提示:对不起,网络太拥挤了!";
          }
      }
      
      

在这里插入图片描述

六、远程调用 Spring Cloud Feign

跳转到目录

前面学习中,使用RestTemplate大大简化了远程调用的代码:

String baseUrl = "http://user-service/user/findById?id=1"+ id;
User user = restTemplate.getForObject(baseUrl, User.class)

如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方
式,来对这些代码再次优化呢?

这就是接下来要学的Feign的功能了。

1.1 简介

Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,是以Java接口的方式调用Http接口,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。

Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

封装了Http调用流程,更符合面向接口化的编程习惯。 类似Dubbo服务调用。

项目主页:https://github.com/OpenFeign/feign

1.2 入门案例

使用Feign替代RestTemplate发送Rest请求。使之更符合面向接口化的编程习惯。

实现步骤:

  1. 导入依赖feign的starter
  2. 启动引导类加@EnableFeignClients注解
  3. 编写FeignClient接口,使用SpringMVC的注解
  4. 在Controller中注入Feign接口,直接调用,无需实现类
  5. 访问接口测试

实现过程:

  1. 导入依赖feign的starter

    <!--配置feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. 启动引导类加@EnableFeignClients注解

    @SpringCloudApplication
    @EnableFeignClients//开启Feign功能
    public class ConsumerApplication {
          
          
        public static void main(String[] args) {
          
          
            SpringApplication.run(ConsumerApplication.class,args);
        }
    }
    

    Feign中已经自动集成Ribbon负载均衡
    在这里插入图片描述

  3. 编写FeignClient接口,使用SpringMVC的注解

    • 在consumer_service中编写Feign客户端接口UserService

    • @FeignClient("user-service")//指定feign调用的服务
      public interface UserService {
              
              
      
          @RequestMapping("/user/findById")
          User findById(@RequestParam("id") Integer id);
      }
      
      • Feign会通过动态代理,帮我们生成实现类。
      • 注解@FeignClient声明Feign的客户端接口,需指明服务名称
      • 接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们逆向生成URL地址然后请求
  4. 在Controller中注入UserService接口,直接调用,无需实现类

@RestController
public class ConsumerController {
    
    
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    UserService userService;
    @Autowired
    DiscoveryClient discoveryClient;

    @RequestMapping("/consumer/{id}")
    public String hello(@PathVariable("id") Integer id){
    
    
        String url = "http://user-service/user/findById?id="+id;
        String jsonResult = restTemplate.getForObject(url, String.class);
        return jsonResult;
    }

    @RequestMapping("/feignconsumer/{id}")
    public User hellofeign(@PathVariable Integer id){
    
    
        return userService.findById(id);
    }
}
  1. 启动测试:访问接口http://localhost:8080/feignconsumer/1,正常获取结果
    在这里插入图片描述

Feign实现原理简单分析:

在这里插入图片描述

1.3 负载均衡

负载均衡是远程过程调用必备的要素。Feign本身集成了Ribbon,因此不需要额外引入依赖,也不需要再注册RestTemplate对象。即可无感知使用负载均衡这一特性。
在这里插入图片描述

Fegin内置Ribbon默认设置了连接超时,是1000毫秒(1秒)。和读取超时时间。我们可以通过手动配置来修改。Ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以修改。

# 连接超时时长
Ribbon.ConnectTimeout: 1000
# 数据通信超时时长
Ribbon.ReadTimeout: 2000
# 当前服务器的重试次数
Ribbon.MaxAutoRetries: 0
# 重试多少次服务
Ribbon.MaxAutoRetriesNextServer: 0
# 是否对所有的请求方式都重试
Ribbon.OkToRetryOnAllOperations: false

1.4 熔断器支持

Feign本身也集成Hystrix熔断器,starter内查看。
在这里插入图片描述

服务降级方法实现步骤:

  1. 在配置文件application.yml中开启feign熔断器支持
  2. 编写FallBack处理类,实现FeignClient客户端接口
  3. 在@FeignClient注解中,指定FallBack处理类。
  4. 测试服务降级效果

实现过程:

  1. 在配置文件application.yml中开启feign熔断器支持:默认关闭

    feign:
    	hystrix:
    		enabled: true # 开启Feign的熔断功能
    
  2. 定义一个类UserServiceFallBack,实现刚才编写的UserFeignClient,作为FallBack的处理类

    @Component//需要注意:一定要注入Spring 容器
    public class UserServiceFallBack implements UserService {
          
          
        @Override
        public User findById(Integer id) {
          
          
            User user = new User();
            user.setId(id);
            user.setUsername("用户不存在!!!");
            return user;
        }
    }
    
  3. 在@FeignClient注解中,指定FallBack处理类。。

    @FeignClient(value = "user-service",fallback = UserServiceFallBack.class)
    public interface UserService {
          
          
    
        @RequestMapping("/user/findById")
        User findById(@RequestParam("id") Integer id);
    }
    
  4. 重启测试:关闭user_service服务,然后在页面访问;http://localhost:8080/feignConsumer/2

在这里插入图片描述

1.5 请求压缩和响应压缩

SpringCloudFeign支持对请求和响应进行GZIP压缩,以提升通信过程中的传输速度。

通过配置开启请求与响应的压缩功能:

# 开启请求压缩
feign.compression.request.enabled: true
# 开启响应压缩
feign.compression.response.enabled: true

也可以对请求的数据类型,以及触发压缩的大小下限进行设置

# 设置压缩的数据类型
feign.compression.request.mime-types:	text/html,application/xml,application/json 
# 设置触发压缩的大小下限
feign.compression.request.min-request-size: 2048 

1.6 配置日志级别

在发送和接收请求的时候,Feign定义了日志的输出定义了四个等级:这里我们配置测试一下。

级别 说明
NONE 不做任何记录
BASIC 只记录输出Http 方法名称、请求URL、返回状态码和执行时间
HEADERS 记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息
FULL 记录Request 和Response的Header,Body和一些请求元数据

实现步骤:

  1. 在application.yml配置文件中开启日志级别配置
  2. 编写配置类,定义日志级别bean。
  3. 在接口的@FeignClient中指定配置类
  4. 重启项目,测试访问

实现过程:

  1. 在consumer_service的配置文件中设置com.itheima包下的日志级别都为debug

    • # com.itheima 包下的日志级别都为Debug
      logging.level:
          com.itheima: debug
      
  2. 在consumer_service编写配置类,定义日志级别

    • @Configuration
      public class FeignConfiguration {
              
              
          @Bean
          public Logger.Level feignLoggerLevel(){
              
              
              //记录所有请求和响应的明细,包括头信息,请求体,元数据
              return Logger.Level.FULL;
          }
      }
      
  3. 在consumer_service的FeignClient中指定配置类

    • @FeignClient(value="user-service",fallback = UserServiceFallBack.class,configuration = FeignConfig.class)
      public interface UserService {
              
              
          @RequestMapping("/user/{id}")
          User queryById(@PathVariable("id") Long id);
      }
      
      
  4. 重启项目,即可看到每次访问的日志

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_37989980/article/details/105846010