天天看點

學習springCloud(八)之Hystrix熔斷機制

在分布式環境下,微服務之間不可避免的發生互相調用的情況,但是沒有一個系統是能保證自身絕對正确的,在服務的調用過程中,很可能面臨服務失敗的問題,是以需要一個公共元件能夠在服務通過網絡請求通路其他微服務時,能對服務失效情況下有很強的容錯能力,對微服務提供保護和監控。

Hystrix是netflix的一個開源項目,他能夠在依賴服務失效的情況下,通過隔離系統依賴的方式,防止服務的級聯失敗(服務的雪崩)

學習springCloud(八)之Hystrix熔斷機制

對于服務的熔斷機制,其實需要考慮兩種情況

  1. 服務提供方存活,但調用接口報錯
  2. 服務提供方本身就出問題了

服務提供方報錯

其實這種情況類似于異常捕獲機制,當出現異常,傳回一個通用的接口封包

【springcloud-provider-product】 複制一份成為【springcloud-provider-product-hystrix】

【springcloud-provider-product-hystrix】修改pom檔案,增加 Hystrix依賴

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
           

【springcloud-provider-product-hystrix】 修改ProductController

package cn.enjoy.controller;
import cn.enjoy.service.IProductService;
import cn.enjoy.vo.Product;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;

@RestController
@RequestMapping("/prodcut")
public class ProductController {

    @Resource
    private IProductService iProductService;

    @Resource
    private DiscoveryClient client ; // 進行Eureka的發現服務

    @RequestMapping(value="/get/{id}")
    @HystrixCommand(fallbackMethod = "getFallback")
    public Object get(@PathVariable("id") long id) {
        Product product = this.iProductService.get(id);
        if(product == null) {
            throw new RuntimeException("該産品已下架!") ;
        }
        return  product;
    }

    public Object  getFallback(@PathVariable("id") long id){
        Product product = new Product();
        product.setProductName("HystrixName");
        product.setProductDesc("HystrixDesc");
        product.setProductId(0L);
        return product;
    }


    @RequestMapping(value="/add")
    public Object add(@RequestBody Product product) {
        return this.iProductService.add(product) ;
    }
    @RequestMapping(value="/list")
    public Object list() {
        return this.iProductService.list() ;
    }


    @RequestMapping("/discover")
    public Object discover() { // 直接傳回發現服務資訊
        return this.client ;
    }
}
           

一旦 get()方法上抛出了錯誤的資訊,那麼就認為該服務有問題

會預設使用“@HystrixCommand”注解之中配置好的fallbackMethod 調用類中的指定方法,傳回相應資料

【springcloud-provider-product-hystrix】修改啟動類,增加對熔斷的支援

package cn.enjoy;
import org.mybatis.spring.annotation.MapperScan;
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.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@MapperScan("cn.enjoy.mapper")
@EnableEurekaClient
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ProductHystrixApp {
    public static void main(String[] args) {
        SpringApplication.run(ProductHystrixApp.class,args);
    }
}
           

測試:localhost:8080/prodcut/get/100 通路

服務失連

在某些情況下,服務提供方并沒有失效,但可能由于網絡原因,服務的消費方并不能調用到服務接口,在這種情況下,直接在服務的提供方提供熔斷機制依然還是不夠的,這方面的處理需要在服務的消費方進行服務的回退(服務的降級)處理

服務的熔斷:熔斷指的是當服務的提供方不可使用的時候,程式不會出現異常,而會出現本地的操作調用,服務的熔斷是在服務消費方實作的,在斷網情況下服務提供方的任何處理都是沒有意義的。

【springcloud-service】新增一個IProductClientService的失敗調用(降級處理)

package cn.enjoy.service.fallback;
import cn.enjoy.service.IProductClientService;
import cn.enjoy.vo.Product;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class IProductClientServiceFallbackFactory implements FallbackFactory<IProductClientService> {
    @Override
    public IProductClientService create(Throwable throwable) {
        return  new IProductClientService() {
            @Override
            public Product getProduct(long id) {
                Product product = new Product();
                product.setProductId(999999L);
                product.setProductName("feign-hystrixName");
                product.setProductDesc("feign-hystrixDesc");
                return  product;
            }

            @Override
            public List<Product> listProduct() {
                return null;
            }

            @Override
            public boolean addPorduct(Product product) {
                return false;
            }
        };
    }
}
           

【springcloud-service】 修改IProductClientService,增加fallback配置

package cn.enjoy.service;
import cn.enjoy.feign.FeignClientConfig;
import cn.enjoy.service.fallback.IProductClientServiceFallbackFactory;
import cn.enjoy.vo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@FeignClient(name = "MICROCLOUD-PROVIDER-PRODUCT",configuration = FeignClientConfig.class,
fallbackFactory = IProductClientServiceFallbackFactory.class)
public interface IProductClientService {
    @RequestMapping("/prodcut/get/{id}")
    public Product getProduct(@PathVariable("id")long id);

    @RequestMapping("/prodcut/list")
    public  List<Product> listProduct() ;

    @RequestMapping("/prodcut/add")
    public boolean addPorduct(Product product) ;

}
           

【springcloud-consumer-feign】 複制一份成為【springcloud-consumer-hystrix】子產品

【springcloud-consumer-hystrix】 修改application.yml配置檔案,啟用hystrix配置

feign:
 hystrix:
    enabled: true
 compression:
  request:
    enabled: true
    mime-types: # 可以被壓縮的類型
     - text/xml
     - application/xml
     - application/json
    min-request-size: 2048 # 超過2048的位元組進行壓縮
           

啟動,服務提供者

通路:http://localhost/consumer/product/get?id=1,能正常通路

關閉,服務提供者

通路:http://localhost/consumer/product/get?id=1,也能正常通路

HystrixDashboard

在hystrix裡面提供一個Dashboard(儀表盤)的功能,他是一種監控的功能,可以利用它來進行整體服務的監控

建立一個子產品【springcloud-consumer-hystrix-dashboard】

【springcloud-consumer-hystrix-dashboard】pom檔案如下

<?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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>enjoy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-hystrix-dashboard</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

    </dependencies>
</project>
           

【springcloud-provider-product-hystrix】 pom檔案確定裡面有健康檢查子產品

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
           

【springcloud-consumer-hystrix-dashboard】 修改application.yml配置檔案

server:
  port: 9001
           

【springcloud-consumer-hystrix-dashboard】 建立一個啟動類

package cn.enjoy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardApp.class,args);
    }
}
           

啟動運作:http://localhost:9001/hystrix

學習springCloud(八)之Hystrix熔斷機制

【springcloud-provider-product-hystrix】 修改applcation.yml檔案

management:
  endpoints:
    web:
      exposure:
        include: '*'
           

【springcloud-provider-product-hystrix】啟動

通路:localhost:8080/actuator/hystrix.stream

http://localhost:9001/hystrix 填寫資訊如下

http://admin:[email protected]:8080/actuator/hystrix.stream

學習springCloud(八)之Hystrix熔斷機制

這個時候對localhost:8080的通路都可以被監控到

Turbine

HystrixDashboard 前面已經知道了,它的主要功能是可以對某一項微服務進行監控,但真實情況下,不可能隻對某一個服務進行監控,更多的是對很多服務進行一個整體的監控,這個時候就需要使用到turbine來完成了。

為了示範監控多個服務子產品,這個時候建立一個子產品【springcloud-provider-user-hystrix】,為簡單起見,這個子產品并不連接配接資料庫,也不做安全控制。

【springcloud-provider-user-hystrix】pom檔案如下

<?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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>enjoy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-user-hystrix</artifactId>
    <dependencies>
        <dependency>
            <groupId>enjoy</groupId>
            <artifactId>springcloud-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>
</project>
           

【springcloud-api】新增一個VO類:Users

package cn.enjoy.vo;
import java.io.Serializable;

public class Users implements Serializable {
    private String name;
    private int age;
    private String sex;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}
           

【springcloud-provider-user-hystrix】 建立一個UserController

package cn.enjoy.controller;

import cn.enjoy.vo.Users;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UserController {
    @RequestMapping("/get/{name}")
    @HystrixCommand
    public  Object get(@PathVariable("name")String name) {
        Users users = new Users();
        users.setName(name);
        users.setAge(18);
        users.setSex("F");
        return users;
    }
}
           

【springcloud-provider-user-hystrix】新增啟動類

package cn.enjoy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableCircuitBreaker
@EnableEurekaClient
public class UsersApp {
    public static void main(String[] args) {
        SpringApplication.run(UsersApp.class,args);
    }
}
           

【springcloud-provider-user-hystrix】修改application.yml配置檔案

server:
 port: 8090

spring:
 application:
   name: springcloud-provider-users


logging:
  level:
    cn.enjoy.mapper: debug

eureka:
  client: # 用戶端進行Eureka注冊的配置
    service-url:
      defaultZone: http://admin:enjoy@eureka1:7001/eureka,http://admin:enjoy@eureka2:7002/eureka,http://admin:enjoy@eureka3:7003/eureka
  instance:
    instance-id: springcloud-provider-users
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 2 # 設定心跳的時間間隔(預設是30秒)
    lease-expiration-duration-in-seconds: 5  # 如果現在超過了5秒的間隔(預設是90秒)

info:
  app.name: springcloud-provider-users
  company.name: enjoy
  build.artifactId: $project.artifactId$
  build.modelVersion: $project.modelVersion$

management:
  endpoints:
    web:
      exposure:
        include: '*'
           

啟動後:

通路位址:http://localhost:8090/users/get/enjoy

hystrix監控位址:http://localhost:8090/actuator/hystrix.stream

前面準備工作完成後,如果想要實作 turbine 的配置,準備一個turbine子產品

新增【springcloud-consumer-turbine】子產品,pom檔案如下

<?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">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>enjoy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-consumer-turbine</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>
    </dependencies>
</project>
           

【springcloud-consumer-turbine】修改application.yml配置檔案

server:
 port: 9101 
eureka:
  client:
    register-with-eureka: false
    service-url:
        defaultZone: http://admin:enjoy@eureka1:7001/eureka,http://admin:enjoy@eureka2:7002/eureka,http://admin:enjoy@eureka3:7003/eureka

turbine:
  app-config: MICROCLOUD-PROVIDER-PRODUCT,MICROCLOUD-PROVIDER-USERS
  cluster-name-expression: new String("default")
           

可以發現對于turbine,其實是從eureka配置在app-config中服務,然後進行監控

【springcloud-consumer-turbine】 建立一個啟動類

package cn.enjoy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.turbine.EnableTurbine;

@SpringBootApplication
@EnableTurbine
public class TurbineApp {
    public static void main(String[] args) {
        SpringApplication.run(TurbineApp.class,args);
    }
}
           

turbine監控位址:

啟動Dashboard: http://localhost:9001/hystrix

在Dashboard裡面填上 turbine監控位址

學習springCloud(八)之Hystrix熔斷機制

發現目前turbine隻監控了UserController的資訊,看下turbine背景發現報錯

學習springCloud(八)之Hystrix熔斷機制

其實原因也很簡單,User服務并不需要使用者驗證,是以能正常通路,但對于Product服務,配置了使用者名密碼的,turbine肯定無法通路

【springcloud-security】如果現在需要turbine進行加密服務的通路,那麼隻能折衷處理,讓通路/actuator/hystrix.stream與/turbine.stream這兩個位址的時候不需要使用者密碼驗證

【springcloud-security】 修改WebSecurityConfiguration

package cn.enjoy.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth)
            throws Exception {
                auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("root").password(new BCryptPasswordEncoder().encode("enjoy")).roles("USER").
                        and().withUser("admin").password(new BCryptPasswordEncoder().encode("enjoy")).roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().anyRequest()
                .fullyAuthenticated();
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/actuator/hystrix.stream","/turbine.stream") ;
    }
}
           

turbine監控位址:http://localhost:9101/turbine.stream

啟動Dashboard: http://localhost:9001/hystrix

在Dashboard裡面填上 turbine監控位址

重新整理:

http://localhost:8080/prodcut/get/1

http://localhost:8090/users/get/1

這就可以正常監控兩個服務了

繼續閱讀