SpringCloud笔记——Hystrix+Hystrix DashBoard

3 篇文章 0 订阅
2 篇文章 0 订阅

hystrix(断路器)ribbon+restTemplate方式

在分布式系统中,根据业务来拆分成一个个的微服务,服务与服务之间可以相互调用(RPC),在spring cloud 中可以用RestTemplate+ribbon和feign来调用。为了保证其高可用,单个服务有时候会集群部署,由于网络或程序自躾 的原因,服务并不能保证百分百可靠可用,如果单个服务出现问题,调用这个服务就出现线程阻塞,此时若有大量的请求涌入,servlet容器的线程资源就会被消耗完毕导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成不可估量的严重后果,这就是常说的服务故障的“雪崩效应”。为了解决这个问题,有人就提出了一种解决问题的思路,断路器模型。就是每一个调用服务的接口处加一个断路器,默认是关闭的,当对服务调用时,不可用的次数达到一个阀值时,断路器就会打开,通过回调方法迅速返回一个值结束调用,避免出现连锁故障。

1.改造上一篇文章的zhangsanService,在pom.xml中加入hystrix的依赖

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

2.改造启动类ZhangsanServiceApplication.java

package com.gaox.zhangsanService;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix//在主启动类开启断路器
@RestController
public class ZhangsanServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(ZhangsanServiceApplication.class, args);
   }
    
   @Bean
   @LoadBalanced
   public RestTemplate restTemplate(){
      return new RestTemplate();
   }

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/hello")
   @HystrixCommand(fallbackMethod = "helloError")//标注调用其它服务接口失败后的回调函数
   public String hello(String name){
      String result=restTemplate.getForObject("http://HELLOSERVICE/hello?name="+name,String.class);
      return result;

   }
    
    //其它服务接口失败后的回调函数
   public String helloError(String name){
      return "hello  ,"+name+"!  sorry ,error !";
   }

}

@HystrixCommand的参数详解

​ 1:commandKey:配置全局唯一标识服务的名称,比如,库存系统有一个获取库存服务,那么就可以为这个服务起一个名字来唯一识别该服务,如果不配置,则默认是@HystrixCommand注解修饰的函数的函数名。

2:groupKey:一个比较重要的注解,配置全局唯一标识服务分组的名称,比如,库存系统就是一个服务分组。通过设置分组,Hystrix会根据组来组织和统计命令的告、仪表盘等信息。Hystrix命令默认的线程划分也是根据命令组来实现。默认情况下,Hystrix会让相同组名的命令使用同一个线程池,所以我们需要在创建Hystrix命令时为其指定命令组来实现默认的线程池划分。此外,Hystrix还提供了通过设置threadPoolKey来对线程池进行设置。建议最好设置该参数,使用threadPoolKey来控制线程池组。

3:threadPoolKey:对线程池进行设定,细粒度的配置,相当于对单个服务的线程池信息进行设置,也可多个服务设置同一个threadPoolKey构成线程组。

4:fallbackMethod:@HystrixCommand注解修饰的函数的回调函数,@HystrixCommand修饰的函数必须和这个回调函数定义在同一个类中,因为定义在了同一个类中,所以fackback method可以是public/private均可。

5:commandProperties:配置该命令的一些参数,如executionIsolationStrategy配置执行隔离策略,默认是使用线程隔离,此处我们配置为THREAD,即线程池隔离。参见:com.netflix.hystrix.HystrixCommandProperties中各个参数的定义。

6:threadPoolProperties:线程池相关参数设置,具体可以设置哪些参数请见:com.netflix.hystrix.HystrixThreadPoolProperties

7:ignoreExceptions:调用服务时,除了HystrixBadRequestException之外,其他@HystrixCommand修饰的函数抛出的异常均会被Hystrix认为命令执行失败而触发服务降级的处理逻辑(调用fallbackMethod指定的回调函数),所以当需要在命令执行中抛出不触发降级的异常时来使用它,通过这个参数指定,哪些异常抛出时不触发降级(不去调用fallbackMethod),而是将异常向上抛出。

8:observableExecutionMode:定义hystrix observable command的模式;

​ 9:raiseHystrixExceptions:任何不可忽略的异常都包含在HystrixRuntimeException中;

​ 10:defaultFallback:默认的回调函数,该函数的函数体不能有入参,返回值类型与@HystrixCommand修饰的函数体的返回值一致。如果指定了fallbackMethod,则fallbackMethod优先级更高。

拓展内容

请求缓存功能

注解描述属性
@CacheResult该注解用来标记请求命令返回的结果应该被缓存,它必须与@HystrixCommand注解结合使用cacheKeyMethod
@CacheRemove该注解用来让请求命令的缓存失效,失效的缓存根据定义Key决定commandKey,cacheKeyMethod
@CacheKey该注解用来在请求命令的参数上标记,使其作为缓存的Key值,如果没有标注则会使用所有参数。如果同事还是使用了@CacheResult和@CacheRemove注解的cacheKeyMethod方法指定缓存Key的生成,那么该注解将不会起作用value

使用@CacheResult开启缓存代码示例:

@Service
public class CacheResultDemo {
 
    @Autowired
    private RestTemplate restTemplate;
 
    @CacheResult(cacheKeyMethod = "getUserId")
    @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
    public User hiConsumer(String id) {
        
        //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
        return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class).getBody();
    }
    
    public String hiConsumerFallBack(String id, Throwable e) {
        return "This is a error";
    }
    
    public String getUserId(String id) {
        return id;
    }
 
}

使用CacheKey开启缓存代码示例:

@Service
public class CacheKeyDemo {
      @Autowired
      private RestTemplate restTemplate;
      @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
      public User hiConsumer(@CacheKey("id") String id) {
            
            //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
            return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class).getBody();
      }
      
      public String hiConsumerFallBack(String id, Throwable e) {
            return "This is a error";
      }
}

其中@CacheKey除了可以指定方法参数为缓存key之外,还可以指定对象中的属性作为缓存Key,如下:

@Service
public class CacheKeyDemo2 {
 
    @Autowired
    private RestTemplate restTemplate;
 
    @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
    public User hiConsumer(@CacheKey("id") User user) {
        
        //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
        return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class, user.getId()).getBody();
    }
    
    public String hiConsumerFallBack(String id, Throwable e) {
        return "This is a error";
    }
 
}

清理失效缓存功能:

​ 使用请求缓存时,如果只是读操作,那么不需要考虑缓存中的内容是否正确的问题,但是如果请求命令中还有更新数据的写操作,那么缓存中的数据就需要我们在进行写操作时进行及时处理,以防止读操作的请求命令获取到了失效的数据。

​ 通过@CacheRemove注解来实现失效缓存清理功能:

@Service
public class CacheRemoveDemo {
      @Autowired
      private RestTemplate restTemplate;
      @CacheRemove(commandKey = "getUserId")
      @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
      public void update(@CacheKey("id") User user) {
            
            //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
            restTemplate.postForObject("http://SERVICE_HI/hi", user, User.class);
            return;
      }
      
      public String hiConsumerFallBack(String id, Throwable e) {
            return "This is a error";
      }
      
      public String getUserId(String id) {
            return id;
      }

hystrix(断路器)feign自带断路器

Application.properties:

server.port=8765
spring.application.name=lisiService
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
#开启断路器
feign.hystrix.enabled=true

在代码中使用实例

package com.gaox.lisiService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@RestController
public class LisiServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(LisiServiceApplication.class, args);
    }

	//标注调用的服务名称和调用失败后的回调函数
    @FeignClient(value = "helloService" ,fallback = HelloError.class)
    public interface HelloService {
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
         String hello(@RequestParam("name") String name);
    }
    
    @Component
    public class HelloError implements HelloService {
        @Override
        public String hello(String name){
            return "hello  ,"+name+"!  sorry ,error !";
        }
    }
    
    @Autowired
   private HelloService helloService;

    @RequestMapping("/hello")
    public String hello(@RequestParam("name")String name){
    return helloService.hello(name);
    }
}

Hystrix服务降级

抽取出服务提供者的接口方法
package com.tongxin.eurekacustomer.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import com.tongxin.eurekacustomer.entity.person;
import com.tongxin.eurekacustomer.service.impl.PersonServiceImpl;

@FeignClient(value="provider",fallbackFactory=PersonServiceImpl.class)
public interface PersonService {
	
	@GetMapping("/person/{id}")
	public person findPeronById(@PathVariable("id")Integer id);
}

@FeignClient中的value是此接口需要调用的生产者的服务名spring.application.name=provider

fallbackFactory是消费者调用后一定时间得不到返回值时的回调函数所在的实现类

回调如下

package com.tongxin.eurekacustomer.service.impl;

import org.springframework.stereotype.Service;

import com.tongxin.eurekacustomer.entity.person;
import com.tongxin.eurekacustomer.service.PersonService;

import feign.hystrix.FallbackFactory;



//必须实现FallbackFactory
@Service//必须放入容器中否则启动会报错
public class PersonServiceImpl implements FallbackFactory<PersonService> {

	@Override
	public PersonService create(Throwable arg0) {
		return new PersonService() {

			@Override
			public person findPeronById(Integer id) {
				person p=new person();
				p.setId(1);
				p.setAge(18);
				p.setName("该服务已关闭!");
				return p;
			}
			
			
		};
	}

	
}

回调方法所在的类必须实现FallbackFactory接口并指定接口类型PersonService,此实现类必须放入IOC容器中,

重写接口的findPeronById方法;

在大型分布式项目中,可将此service抽取为公用的service接口,为所有的微服务所调用

在前端控制层(controller)注入上面写的接口,调用方法。
package com.tongxin.eurekacustomer.controller;

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 com.tongxin.eurekacustomer.entity.person;
import com.tongxin.eurekacustomer.service.PersonService;

@RestController
public class PersonController {

	@Autowired
	PersonService personService;

	@GetMapping("/person/{id}")
	public person findPersonById(@PathVariable("id") Integer id) {
		person person =personService.findPeronById(id);
		return person;
	}
}

Hystrix DashBoard监控面板

一、项目创建

1、创建Spring Boot 工程,命名为:hystrix-dashboard,引入如下依赖

<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>

2、在 Spring Boot 的启动类上面引入注解@EnableHystrixDashboard,启用 Hystrix Dashboard 功能。

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

3、修改配置文件 application.yml

server:
  port: 9001
spring:
  application:
    name: hystrix-dashboard

二、页面介绍

启动应用,然后再浏览器中输入 http://localhost:9001/hystrix 可以看到如下界面

通过 Hystrix Dashboard 主页面的文字介绍,我们可以知道,Hystrix Dashboard 共支持三种不同的监控方式:

默认的集群监控:通过 URL:http://turbine-hostname:port/turbine.stream 开启,实现对默认集群的监控。
指定的集群监控:通过 URL:http://turbine-hostname:port/turbine.stream?cluster=[clusterName] 开启,实现对 clusterName 集群的监控。
单体应用的监控: 通过 URL:http://hystrix-app:port/hystrix.stream 开启 ,实现对具体某个服务实例的监控。(现在这里的 URL 应该为 http://hystrix-app:port/actuator/hystrix.stream,Actuator 2.x 以后endpoints 全部在/actuator下,可以通过management.endpoints.web.base-path修改)。

前两者都对集群的监控,需要整合 Turbine 才能实现。这一部分我们先实现对单体应用的监控,这里的单体应用就用使用 Hystrix 实现的服务提供者——provider。

页面上的另外两个参数:

Delay:控制服务器上轮询监控信息的延迟时间,默认为 2000 毫秒,可以通过配置该属性来降低客户端的网络和 CPU 消耗。
Title:该参数可以展示合适的标题。

三、为服务提供者provider添加 endpoint

既然 Hystrix Dashboard 监控单实例节点需要通过访问实例的/actuator/hystrix.stream接口来实现,自然我们需要为服务实例添加这个 endpoint。

**1、POM 配置 **
在服务的pom.xml中的dependencies节点中新增spring-boot-starter-actuator监控模块以开启监控相关的端点,并确保已经引入断路器的依赖spring-cloud-starter-netflix-hystrix

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

**2、启动类 **
为启动类添加@EnableCircuitBreaker或@EnableHystrix注解,开启断路器功能。

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableDiscoveryClient
@EnableCircuitBreaker
public class TestEurekaCustomerApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestEurekaCustomerApplication.class, args);
	}

}

3、 配置文件
在配置文件 application.yml 中添加

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

management.endpoints.web.exposure.include这个是用来暴露 endpoints 的。由于 endpoints 中会包含很多敏感信息,除了 health 和 info 两个支持 web 访问外,其他的默认不支持 web 访问。

测试
在 Hystrix-Dashboard 的主界面上输入 服务提供者provider 对应的地址 http://localhost:8087/actuator/hystrix.stream 然后点击 Monitor Stream 按钮,进入页面。

如果没有请求会一直显示 “Loading…”,这时访问 http://localhost:8087/actuator/hystrix.stream 也是不断的显示 “ping”。


这时候访问一下 http://localhost:8087/dept/get/1,监控面板会发生变化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值