学习springCloud(八)之Hystrix熔断机制

在分布式环境下,微服务之间不可避免的发生互相调用的情况,但是没有一个系统是能保证自身绝对正确的,在服务的调用过程中,很可能面临服务失败的问题,因此需要一个公共组件能够在服务通过网络请求访问其他微服务时,能对服务失效情况下有很强的容错能力,对微服务提供保护和监控。

Hystrix是netflix的一个开源项目,他能够在依赖服务失效的情况下,通过隔离系统依赖的方式,防止服务的级联失败(服务的雪崩)
在这里插入图片描述
对于服务的熔断机制,其实需要考虑两种情况

  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-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:enjoy@localhost:8080/actuator/hystrix.stream
在这里插入图片描述
这个时候对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监控地址
在这里插入图片描述
发现目前turbine只监控了UserController的信息,看下turbine后台发现报错
在这里插入图片描述
其实原因也很简单,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

这就可以正常监控两个服务了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值