• springcloud(五) Hystrix 降级,超时


     分布式系统中一定会遇到的一个问题:服务雪崩效应或者叫级联效应
    什么是服务雪崩效应呢?
      在一个高度服务化的系统中,我们实现的一个业务逻辑通常会依赖多个服务,比如:
    商品详情展示服务会依赖商品服务, 价格服务, 商品评论服务. 调用三个依赖服务会共享商品详情服务的线程池. 如果其中的商品评论服务不可用, 就会出现线程池里所有线程都因等待响应而被阻塞, 从而造成服务雪崩. 如图所示:

    简单理解: 就是商品评论服务耗时假如是15S,那么在高并发的时候,其他服务很快就做出响应并把线程回收但是商品评论服务需要10S。在这10S内100个线程都会集中被消耗在商品评论服务,就造成商品评论服务没有线程对外提供服务了。
    服务雪崩效应:因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过
    程,就叫服务雪崩效应

    导致服务不可用的原因有几点: 程序Bug,大流量请求,硬件故障,缓存击穿
    【大流量请求】:在秒杀和大促开始前,如果准备不充分,瞬间大量请求会造成服务提供者的不可用.
    【硬件故障】:可能为硬件损坏造成的服务器主机宕机, 网络硬件故障造成的服务提供者的不可访问.
    【缓存击穿】:一般发生在缓存应用重启, 缓存失效时高并发, 所有缓存被清空时,以及短时间内大量缓存失效时. 大量的缓存不命中, 使请求直击后端,造成服务提供者超负荷运行,引起服务不可用。
    用户重试/代码逻辑重试,用户重试:在服务提供者不可用后, 用户由于忍受不了界面上长时间的等待,会不断刷新页面甚至提交表单,或者是代码有重试策略等等
    那么,归根结底导致雪崩效应的最根本原因是:大量请求线程同步等待造成的资源耗尽

    解决方案
    1. 超时机制
    2. 服务限流
    3. 服务熔断
    4. 服务降级 

    先启动Eureka 注册中心,代码就不上了,截图:


    order微服务工程

    pom.xml :

    <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.tuling.cloud</groupId>
      <artifactId>microservice-consumer-order-ribbon-hystrix-fallback</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>06-ms-consumer-order-ribbon-hystrix-fallback</name>
    
      <!-- 引入spring boot的依赖 -->
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
      </parent>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
      </properties>
    
      <dependencies>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    
        <!-- <artifactId>spring-cloud-starter-eureka</artifactId> 依赖了 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> -->
        <!--  此包包含了eurekaclient,ribbon-->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    
        <!-- hystrix 依赖-->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    
        <!-- feign 依赖-->
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    
      </dependencies>
    
      <!-- 引入spring cloud的依赖 -->
      <dependencyManagement>
        <dependencies>
          <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
          </dependency>
        </dependencies>
      </dependencyManagement>
    
      <!-- 添加spring-boot的maven插件 -->
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    </project>
    

      OrderController.java:

    package com.jiagoushi.cloud.study.user.controller;
    
    import com.jiagoushi.cloud.study.user.entity.User;
    import com.jiagoushi.cloud.study.user.feign.UserFeignClient;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    
    /**
     * 演示 user服务挂了超时和执行请求超时
     */
    @RestController
    public class OrderController {
      private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
    
      @Autowired
      private UserFeignClient userFeignClient;
    
      @Autowired
      private RestTemplate restTemplate;
    
      /**
       * Hystrix调用接口默认1秒超时,超时后会自动执行降级方法,可在文件配置,配置文件配置是全局的,
       * @HystrixCommand(fallbackMethod = "findByIdFallback") 注解也可以配置超时
       */
      @HystrixCommand(fallbackMethod = "findByIdFallback") // 基于注解的hystrix 推荐使用
      @GetMapping("/user/{id}")
      public User findById(@PathVariable Long id) {
    	logger.info("================请求用户中心接口==============");
        return this.restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
      }
    
      // 降级的方法
      public User findByIdFallback(Long id) { 
        User user = new User();
        user.setId(-1L);
        user.setName("降级用户");
        return user;
      }
    
    }
    

      ConsumerOrderApplication.java:

    package com.jiagoushi.cloud.study;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.cloud.netflix.feign.EnableFeignClients;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableCircuitBreaker//开启断路器功能
    public class ConsumerOrderApplication {
    
      @Bean
      @LoadBalanced
      public RestTemplate restTemplate() {
        return new RestTemplate();
      }
    
      public static void main(String[] args) {
        SpringApplication.run(ConsumerOrderApplication.class, args);
      }
    }
    

     


    user微服务:

    package com.tuling.cloud.study.controller;
    
    import java.util.Random;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.serviceregistry.Registration;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.tuling.cloud.study.entity.User;
    import com.tuling.cloud.study.repository.UserRepository;
    
    @RestController
    public class UserController {
    	
      private final Logger logger = Logger.getLogger(getClass());
    	
      @Autowired
      private UserRepository userRepository;
      @Autowired
      private Registration registration;
      
    
      @GetMapping("/{id}")
      public User findById(@PathVariable Long id) throws Exception {
    	  logger.info("用户中心接口:查询用户"+ id +"信息");
    	  //模拟系统执行速度很慢的情况
    	  Thread.sleep(5000);
    	  
    	  User findOne = userRepository.findOne(id);
    	  return findOne;
      }
      
      @GetMapping("/getIpAndPort")
      public String findById() {
    	  return registration.getHost() + ":" + registration.getPort();
      }
    }
    

      user微服务在停止或者阻塞5s 的时候,order服务会走降级方法

     

    如何想修改接口超时间时间可以在order调用方修改yml 文件:

    server:
      port: 9010
    spring:
      application:
        name: microservice-consumer-order
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 3000 #命令执行超时时间,默认1000ms,就是调接口的响应时间超过3S就执行降级,不管提供者是否挂机还是延迟超过时间就走降级
  • 相关阅读:
    java 大数据处理类 BigDecimal 解析
    关于纠正 C/C++ 之前在函输内改变 变量的一个错误想法。
    C++ 制作 json 数据 并 传送给服务端(Server) 的 php
    介绍一个很爽的 php 字符串特定检索函数---strpos()
    如何 判断 设备 是否 连接 上 了 wifi
    android 通过访问 php 接受 or 传送数据
    正则匹配抓取input 隐藏输入项和 <td>标签内的内容
    手把手教你Chrome扩展开发:本地存储篇
    HTML5之本地存储localstorage
    初尝CDN:什么是分布式服务节点?
  • 原文地址:https://www.cnblogs.com/smallFishs/p/10600517.html
Copyright © 2020-2023  润新知