微服务之Hystrix熔断器

分布式系统中,服务与服务之间的依赖错综复杂,不可避免,其中一些服务会出现故障 ,导致依赖他们的其他服务出现远程调度的线程问题(雪崩效应)。而Hystrix提供的熔断器,通过隔离服务的访问点,能阻止这种分布式系统中出现的联动故障,并提供故障的解决方案,从而提高了整个分布式系统的弹性。


什么是Hystrix

Hystrix是Netflix公司的开源项目,它提供熔断器功能,能够阻止分布式系统中出现联动故障。Hystrix是通过隔离服务的访问点阻止联动故障的,并提供故障的解决方案,从而提高整个分布式系统的弹性
Hystrix设计原则

  1. 防止单个服务的故障耗尽整个servlet的资源
  2. 快速失败机制,如果某个服务出现故障,则调用该服务的请求快速失败,而不是等待
  3. 提供回退方案fallback,请求故障时,提供设计好的回退方案
  4. 使用熔断机制,防止扩散到其他服务去
  5. 提供熔断器的监控机制Hystrix Dashboard,可以实时监控熔断器状态

工作机制

  1. 当某个API接口失败的次数在一定时间内小于设定的阀值时,熔断器处于关闭状态,该API正常提供服务。
  2. 当失败次数大于设定的阀值的时候,Hystrix判定改API接口出现故障,打开熔断器,这时候该请求API接口会执行快速失败的逻辑(fallback回退的逻辑)而不执行业务逻辑,请求的线程不会处于阻塞状态。
  3. 处于打开状态的熔断器,一段时间后会处于半打开状态,并将一定数量的请求执行业务逻辑,剩余的请求会执行快速失败。若执行的业务逻辑请求失败,则熔断器继续打开,若成功则熔断器关闭。

RestTemplate+Ribbon上使用熔断器

  1. 引入依赖starter-hystrix后,在启动类加上@EnableHystrix注解就可以开启熔断器功能
  2. 在方法上添加@HystrixCommand注解,设置fallBackMethod属性,指定fallback回调,最好返回一些静态字符串,不需要处理复杂逻辑什么的,这样可以方便执行快速失败,释放线程资源。

小demo(注:代码接微服务之Sring Cloud使用Feign实现负载均衡&Feign简介一期博客:

微服务之Hystrix熔断器_第1张图片

 基本步骤:

  1. 创建Hystrix模块
  2. 配置pom.xml
  3. 创建application.yml配置文件
  4. 创建ProductClientService接口、ProductClientServiceImpl实现类
  5. 创建ProductMapper接口
  6. 创建ProductController类
  7. 配置mybatis
  8. 创建ProductProvider_8002_hystrix主启动类
  9. 测试

细节实现:

  1. 创建名为microService-provider-hystrix-8002的Maven项目

  2. 配置pom.xml文件

    
        
        
            cn.zf
            microService-api
            1.0-SNAPSHOT
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-test
        

        
            junit
            junit
        
        
            mysql
            mysql-connector-java
        
        
            com.alibaba
            druid
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
    

  3.  在src/main/resources下创建application.yml配置文件

server:
  port: 8002  # 设置端口号
mybatis:
  cn.zf.springcloud.config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
  type-aliases-package: cn.zf.springcloud.entities # 所有Entity别名类所在包
  mapper-locations: classpath:mybatis/mapper/**/*.xml # mapper映射文件
spring:
  application:
    name: microservice-product  #微服务整合的命名,对外暴露的名字,非常重要
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
    driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动包
    # springcloud_db02数据库名
    url: jdbc:mysql://127.0.0.1:3306/springcloud_db02?serverTimezone=GMT%2B8
    username: root  # 数据库用户名
    password: 123456  # 数据库密码
    dbcp2:
      min-idle: 5 # 数据库连接池的最小维持连接数
      initial-size: 5 # 初始化连接数
      max-total: 5 # 最大连接数
      max-wait-millis: 150 # 等待连接获取的最大超时时间
eureka:
  client: # 客户端注册进eureka服务列表内
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:     # 注册到哪个服务中心
      defaultZone: http://eureka6001.com:6001/eureka,http://eureka6002.com:6002/eureka
  instance:
    instanceId: ${spring.application.name}:${server.port}-hystrix      # 在注册中心隐藏主机名
    prefer-ip-address: true # 访问路径可以显示ip地址

  4.  在src/main/resources下创建mybatis目录并引入mybatis.cfg.xml配置文件




    
    
        
    

  5. 在src/main/resources/mybatis下创建mapper目录并引入productMapper.xml配置文件




    
    
    
    
        INSERT  INTO product(product_name,db_source) VALUES (#{productName},DATABASE())
    

   6. 创建mapper接口

package cn.zf.springcloud.mapper;

import cn.zf.springcloud.entities.Product;

import java.util.List;

/*
dao持久层接口
 */
public interface ProductMapper {
    Product findById(Long id);
    List findAll();
    boolean addProduct(Product product);
}

  7. 创建service服务层,接口、实现类

package cn.zf.springcloud.service;

import cn.zf.springcloud.entities.Product;

import java.util.List;

/*
service业务层接口
 */
public interface ProductService {
    boolean add(Product product);
    Product get(Long id);
    List list();
}

 

package cn.zf.springcloud.service.impl;

import cn.zf.springcloud.entities.Product;
import cn.zf.springcloud.mapper.ProductMapper;
import cn.zf.springcloud.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/*
service业务层实现类
 */
@Service
public class ProductServiceImpl implements ProductService {
    //注入dao层对象,调用dao层接口
    @Autowired
    private ProductMapper productMapper;
    @Override
    public boolean add(Product product) {
        return productMapper.addProduct(product);
    }

    @Override
    public Product get(Long id) {
        return productMapper.findById(id);
    }

    @Override
    public List list() {
        return productMapper.findAll();
    }
}

  8. 创建controller控制层

package cn.zf.springcloud.controller;

import cn.zf.springcloud.entities.Product;
import cn.zf.springcloud.service.ProductService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//@RestController响应数据转json
@RestController
public class ProductController {
    //注入service层的对象,调用service层的方法
    @Autowired
    private ProductService productService;
    @RequestMapping(value = "/product/add",method = RequestMethod.POST)
    //@RequestBody将传过来的json数据转java中的类型数据
    public boolean add(@RequestBody Product product){
        return productService.add(product);
    }
    //当get方法出现异常时 则会调用hystrixGet方法进行处理
    @HystrixCommand(fallbackMethod = "getFallback")
    @RequestMapping(value = "/product/get/{id}",method = RequestMethod.GET)
    //@PathVariable获取路径中的参数
    public Product get(@PathVariable("id") Long id){
        Product product = productService.get(id);
        if (product==null){
            throw new RuntimeException("id"+id+"无效");
        }
        System.out.println(product);
        return product;
    }
    //当出现异常是调用getFallback
    public Product getFallback(@PathVariable("id")Long id){
        return new Product(id,"id"+id+"无效--@HystrixCommand","无效的数据");
    }
    @RequestMapping(value = "/product/list",method = RequestMethod.GET)
    public List list(){
        return productService.list();
    }
}

  9. 创建ProductProvider_8002_hystrix主启动类

package cn.zf.springcloud;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

@EnableHystrix    // 开启Hystrix 熔断机制的支持
@EnableEurekaClient
//@MapperScan指定要扫描的Mapper类的包的路径
@MapperScan("cn.zf.springcloud.mapper")
@SpringBootApplication
public class ProductProvider_8002_hystrix {
    public static void main(String[] args) {
        SpringApplication.run(ProductProvider_8002_hystrix.class,args);
    }
}

  10. 测试,先启动两个eureka注册中心的主启动类(两个注册中心顺序无所谓),再启动服务提供者ProductProvider_8002_hystrix主启动类,最后启动服务消费者ProductConsumer_80主启动类

微服务之Hystrix熔断器_第2张图片

微服务之Hystrix熔断器_第3张图片


Feign上使用熔断器

  • 创建Fegin模块
  • 配置pom.xml
  • 创建application.yml配置文件
  • 创建自定义Rest相关配置类ConfigBean
  • 创建ProductClientService接口、实现类
  • 创建ProductController_Feign
  • 创建ProductConsumer_80_Fegin主启动类
  • 测试

微服务之Hystrix熔断器_第4张图片

  1. 创建名为microService-consumer-feign的Maven项目

  2. 配置pom.xml文件

    
        
        
            cn.zf
            microService-api
            1.0-SNAPSHOT
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
    

  3. 在src/main/resources下创建application.yml配置文件

server:
  port: 80
eureka:
  client:
    register-with-eureka: false
    fetch-registry: true     #发现服务中  获得注册信息
    serviceUrl:
      defaultZone: http://eureka6001.com:6001/eureka,http://eureka6002.com:6002/eureka
feign:
  hystrix:
    enabled: true #在feign上使用hystrix

  4. 在src/main/java下创建自定义Rest相关配置类ConfigBean

package cn.zf.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * Rest相关配置类访问RestFull的方法(url,requestMap,ResponseBean.class)
 */
@Configuration
public class ConfigBean {
    // 向容器中添加RestTemplate组件  直接通过该组件可以调用REST接口
    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

  5. 在src/main/java下创建ProductClientService接口、ProductClientServiceFallBack实现类

package cn.zf.springcloud.service;

import cn.zf.springcloud.entities.Product;
import cn.zf.springcloud.service.impl.ProductClientServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@FeignClient(value = "MICROSERVICE-PRODUCT",fallback = ProductClientServiceFallBack.class)
public interface ProductClientService {
    @RequestMapping(value = "/product/get/{id}",method = RequestMethod.GET)
    //使用熔断器,加@PathVariable("id")
    Product get(@PathVariable("id") Long id);
    @RequestMapping(value = "/product/list",method = RequestMethod.GET)
    List list();
    @RequestMapping(value = "/product/add",method = RequestMethod.POST)
    boolean add(Product product);
}
package cn.zf.springcloud.service.impl;

import cn.zf.springcloud.entities.Product;
import cn.zf.springcloud.service.ProductClientService;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ProductClientServiceFallBack implements ProductClientService {
    @Override
    public Product get(Long id) {
        return new Product(id,"id="+id+"无数据--fegin&hystrix","无有效数据库");
    }

    @Override
    public List list() {
        return null;
    }

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

  6. 在src/main/java下创建ProductController_Fegin

package cn.zf.springcloud.controller;

import cn.zf.springcloud.entities.Product;
import cn.zf.springcloud.service.ProductClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ProductorController_Feign {
    @Autowired
    private ProductClientService service;
    @RequestMapping(value = "/consumer/product/add")
    public boolean add(Product product){
        return service.add(product);
    }
    @RequestMapping(value = "/consumer/product/get/{id}")
    public Product get(@PathVariable("id") Long id){
        Product product = service.get(id);
        if (product==null){
           throw new RuntimeException("id"+id+"无效数据");
        }
        return product;
    }
    @RequestMapping(value = "/consumer/product/list")
    public List list(){
        return service.list();
    }
}

  7. 创建ProductConsumer_80_Feign主启动类

package cn.zf.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients(basePackages = {"cn.zf.springcloud"})
@EnableEurekaClient   // 向注册中心进行注册
@SpringBootApplication
public class ProductConsumer_80_Feign {
    public static void main(String[] args) {
        SpringApplication.run(ProductConsumer_80_Feign.class,args);
    }
}

  8. 测试,先启动两个eureka注册中心的主启动类(两个注册中心顺序无所谓),再启动基于熔断器的服务提供者的主启动类,最后启动ProductConsumer_80_Feign服务消费者的主启动类

微服务之Hystrix熔断器_第5张图片

微服务之Hystrix熔断器_第6张图片

over~ 

你可能感兴趣的:(微服务,Spring,Cloud,Hystrix)