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就執行降級,不管提供者是否掛機還是延遲超過時間就走降級

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM