目录
4.3 配置文件application.yml增加feign的hystrix开启功能
4.4.1 feign调用接口GoodsFeignHystrixRemoteService
4.4.2 GoodsFeignHystrixRemoteServiceFallBack
4.4.2 GoodsFeignHystrixRemoteServiceFallBackFacttory
一、Hystrix有什么作用?
随着技术的发展,越来越多的项目采用微服务分布式架构;这些服务之间有时需要相互调用的,并且为了保持高可用的状态,是需要集群部署的。但是这些服务之间的调用,因为网络原因和自身存在的一些问题,是不能保证100%调用成功的。如果调用失败,但同时又有大量的请求进来,会占用过多的资源导致服务瘫痪,因为微服务之间是相互调用的,因此可能会导致多个服务都不可用,造成服务雪崩。
Hystrix是一个用于分布式服务调用的断路器,可以在服务调用超时、异常等情况下进行服务降级和限流,这样就避免了服务调用方的线程不被长时间、不必要的占用,避免了资源的过度占用,造成分布式服务的雪崩。
二、Hystrix使用注意事项
2.1 Hystrix默认超时时间是1秒
2.2 Hystrix超时时间设置分为两种
- 注解配置
- 配置文件配置
2.3 HystrixCommand注解
- fallbackMethod:配置回调方法,即服务降级方法
- ignoreExceptions:配置不进入降级方法的异常
- commandProperties:hystrix属性设置,包括超时设置
- threadPoolkey:线程池唯一标识
- threadPoolProperties:线程池属性设置,包括核心线程树和队列大小,可以做限流
三、Hystrix使用
3.1 项目目录结构
3.2 portal-server修改
3.2.1 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">
<parent>
<artifactId>spring-cloud-study</artifactId>
<groupId>com.wj</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>portal-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.wj</groupId>
<artifactId>cloud-common-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--引入hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
3.2.2 启动类开启Hystrix
- 注解@EnableCircuitBreaker和注解@EnableHystrix的作用相同,开启Hystrix断路器
- 注解@SpringCloudApplication注解相当于@EnableCircuitBreaker、@EnableHystrix和@SpringBootApplication的集合
package com.wj.portal.server;
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;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
/**
* @EnableDiscoveryClient和@EnableEurekaClient共同点:让注册中心发现,扫描到该服务。
* 不同点:@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心,比如zookeeper。
* @EnableCircuitBreaker和@EnableHystrix的作用是一样的,开启断路器;
* @SpringCloudApplication:此注解的作用相当于@EnableCircuitBreaker、@EnableDiscoveryClient和@SpringBootApplication
* @author wangjian
*/
//开启eureka客户端
@EnableEurekaClient
//@EnableDiscoveryClient
@EnableFeignClients("com.wj.common.api.feign")//开启feign,并配置扫描路径
@SpringBootApplication
@EnableHystrix//启用hystrix
//@EnableCircuitBreaker
//@SpringCloudApplication
@ComponentScan(value = {"com.wj.portal.server.*","com.wj.common.api.*"})
public class PortalServerApplication {
public static void main(String[] args) {
SpringApplication.run(PortalServerApplication.class,args);
}
}
3.2.3 application.yml配置文件
- Hystrix的超时配置可在配置文件和注解中配置,两者只需要配置其一
# 端口号配置
server:
port: 9100
# 应用名称配置
spring:
application:
name: portal-server
#eureka客户端配置
eureka:
instance:
# 向注册中心发送心跳间隔时间,告诉注册中心自己还活着;默认时间是30s
lease-renewal-interval-in-seconds: 10
# 如果30秒内没有向注册中心发送心跳,代表发生故障,从注册中心移除掉,默认时间是90s
lease-expiration-duration-in-seconds: 30
#告诉服务端,服务实例以ip作为连接,而不是机器名,默认是false
prefer-ip-address: true
#告诉服务端,服务实例的名称
instance-id: ${spring.application.name}
client:
#注册中心连接地址
service-url:
defaultZone: http://127.0.0.1:8761/eureka/,http://localhost:8762/eureka/
#hystrix配置
#hystrix的超时时间可在配置文件或注解配置
#hystrix.command.default.execution.timeout.enabled说明:
#为true时,需两个方法配置超时设置,分别是Ribbon的ReadTimeout和hystrix的timeoutInMilliseconds,以值小的为准
#为false时,hystrix不进行超时熔断,根据Ribbon的ReadTimeout抛出的异常进行熔断,具体情况取决于ribbon的connectTimeout配置的超时时间和其他情况为准
hystrix:
command:
default:
execution:
timeout:
enabled: true #为true时,需两个方法配置超时设置,分别是Ribbon的ReadTimeout和hystrix的timeoutInMilliseconds,以值小的为准
isolation:
thread:
timeoutInMilliseconds: 5000
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
3.2.4 HystrixController
package com.wj.portal.server.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.wj.common.api.base.Result;
import com.wj.common.api.entity.Goods;
import com.wj.common.api.feign.GoodsRemoteService;
import com.wj.portal.server.constants.GoodsUrlConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* hystrix控制器
* @author wangjian
*/
@RestController
@RequestMapping("/hystrix")
public class HystrixController {
//注入RestTemplate
@Autowired
private RestTemplate restTemplate;
/**
* hystrix调用获取产品列表
* hystrix说明:
* 1.默认超时时间是1秒
* 2.超时时间设置有两种方式,配置一种即可:
* 2.1 注解配置:具体详情见下方注解配置
* 2.2 配置文件配置:具体情况见配置文件
* 3.可以用作限流:
* 3.1 threadPoolKey:线程池唯一标识
* 3.2 threadPoolProperties:线程池配置
* @HystrixCommand说明:
* 1.fallbackMethod:配置服务降级方法
* 2.ignoreExceptions:配置抛出的异常不进入服务降级方法
* 3.commandProperties:配置hystrix超时设置
* @return
*/
@HystrixCommand(
//降级方法配置
fallbackMethod = "fallback",
//忽略异常配置
ignoreExceptions = {Throwable.class,Exception.class},
//超时配置
commandProperties = {
@HystrixProperty(name = "execution.timeout.enabled",value = "true"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
},
//线程池配置
threadPoolKey = "limit",
threadPoolProperties = {
@HystrixProperty(name = "coreSize",value ="2"),
@HystrixProperty(name = "maxQueueSize",value = "1")
}
)
@GetMapping("/goods/hystrix/list")
public Result<List<Goods>> feignList(){
//设置4秒,测试超时降级
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 默认情况下,不论是此方法,还是远程调用的方法发生异常或超时,都会进行服务降级,
* 除非配置了忽略异常,调用的时长小于配置的时长不会进行服务降级
*/
//远程调用
ResponseEntity<Result> forEntity = restTemplate.getForEntity(GoodsUrlConstant.GOODS_LIST_URL, Result.class);
Result result = forEntity.getBody();
//测试调用者抛出异常降级
// throw new RuntimeException("运行异常");
return result;
}
/**
* 回调降级方法
* throwable:抛出的异常
* 说明:
* 1.默认情况,不论是服务调用者还是服务提供者抛出异常都会进行服务降级
* 2.回调降级方法加上Throwable,可以捕获到抛出的异常
* @return
*/
public Result<List<Goods>> fallback(Throwable throwable){
throwable.printStackTrace();
return Result.error(400,"服务降级!");
}
}
3.3 测试结果
四、Feign整合Hystrix使用
4.1 说明
- SpringCloud Dalston版本默认关闭,需配置打开,不然feign调用不能熔断降级;
- SpringCloud新的版本feign调用同一个服务必须写在同一个feign调用接口中,具体从哪一个版本开始的没有去验证
- feign的声明接口的Fallback和FallbackFactory只能用一个,两个同时配置,只能Fallback生效,FallbackFactory不能生效
4.2 @FeignClient注解
- value:指定调用的服务在注册中心的名称
- fallback:指定feign调用失败降级的接口实现类
- fallbackFactory:捕获降级的具体异常
4.3 配置文件application.yml增加feign的hystrix开启功能
# 端口号配置
server:
port: 9100
# 应用名称配置
spring:
application:
name: portal-server
#eureka客户端配置
eureka:
instance:
# 向注册中心发送心跳间隔时间,告诉注册中心自己还活着;默认时间是30s
lease-renewal-interval-in-seconds: 10
# 如果30秒内没有向注册中心发送心跳,代表发生故障,从注册中心移除掉,默认时间是90s
lease-expiration-duration-in-seconds: 30
#告诉服务端,服务实例以ip作为连接,而不是机器名,默认是false
prefer-ip-address: true
#告诉服务端,服务实例的名称
instance-id: ${spring.application.name}
client:
#注册中心连接地址
service-url:
defaultZone: http://127.0.0.1:8761/eureka/,http://localhost:8762/eureka/
#hystrix配置
#hystrix的超时时间可在配置文件或注解配置
#hystrix.command.default.execution.timeout.enabled说明:
#为true时,需两个方法配置超时设置,分别是Ribbon的ReadTimeout和hystrix的timeoutInMilliseconds,以值小的为准
#为false时,hystrix不进行超时熔断,根据Ribbon的ReadTimeout抛出的异常进行熔断,具体情况取决于ribbon的connectTimeout配置的超时时间和其他情况为准
hystrix:
command:
default:
execution:
timeout:
enabled: true #为true时,需两个方法配置超时设置,分别是Ribbon的ReadTimeout和hystrix的timeoutInMilliseconds,以值小的为准
isolation:
thread:
timeoutInMilliseconds: 5000
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
#feign整合hystrix配置
#SpringCloud Dalston版本默认关闭,需配置打开,不然feign调用不能熔断降级
feign:
hystrix:
enabled: true
4.4 Feign声明式调用接口
4.4.1 feign调用接口GoodsFeignHystrixRemoteService
package com.wj.common.api.feign;
import com.wj.common.api.base.Result;
import com.wj.common.api.entity.Goods;
import com.wj.common.api.feign.factory.GoodsFeignHystrixRemoteServiceFallBackFacttory;
import com.wj.common.api.feign.fallback.GoodsFeignHystrixRemoteServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
/**
* Feign整合Hystrix
* fallback:指定降级的fallback
* fallbackFactory:捕获降级的具体异常
* 注意问题:
* 需要调用同一个服务的不同方法时,需写在同一个feign调用接口内,
* 否则会出现异常:
* "The bean 'goods-server.FeignClientSpecification', defined in null,
* could not be registered. A bean with that name has already been defined in null and overriding is disabled."
* 这里都是调用goods-server的服务,我写在了两个feign接口中:GoodsFeignHystrixRemoteService和GoodsRemoteService
* 是为了区分feign组件和feign整合Hystrix的用法,因此启动项目时,需要注释掉一个
* @author wangjian
*/
@FeignClient(value = "goods-server",/*fallback = GoodsFeignHystrixRemoteServiceFallBack.class,*/
fallbackFactory = GoodsFeignHystrixRemoteServiceFallBackFacttory.class)
public interface GoodsFeignHystrixRemoteService {
/**
* feign整合hystrix产品提供者
* 获取产品列表
* @return
*/
@GetMapping("/feignHystrix/goods/list")
public Result<List<Goods>> feignHystrixList();
/**
* feign整合hystrix产品提供者
* 获取产品详情
* @return
*/
@GetMapping("/feignHystrix/goods/info")
Result<Goods> feignHystrixInfo();
}
4.4.2 GoodsFeignHystrixRemoteServiceFallBack
package com.wj.common.api.feign.fallback;
import com.wj.common.api.base.Result;
import com.wj.common.api.entity.Goods;
import com.wj.common.api.feign.GoodsFeignHystrixRemoteService;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* feign整合hystrix,服务降级
* @author wangjian
*/
@Component
public class GoodsFeignHystrixRemoteServiceFallBack implements GoodsFeignHystrixRemoteService {
@Override
public Result<List<Goods>> feignHystrixList() {
return Result.ok("goods-server服务降级!");
}
@Override
public Result<Goods> feignHystrixInfo() {
return Result.ok("goods-server服务降级!");
}
}
4.4.2 GoodsFeignHystrixRemoteServiceFallBackFacttory
package com.wj.common.api.feign.factory;
import com.wj.common.api.base.Result;
import com.wj.common.api.entity.Goods;
import com.wj.common.api.feign.GoodsFeignHystrixRemoteService;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* feign整合hystrix异常处理,获取具体的服务错误信息
* @author wangjian
*/
@Component
public class GoodsFeignHystrixRemoteServiceFallBackFacttory implements FallbackFactory<GoodsFeignHystrixRemoteService> {
@Override
public GoodsFeignHystrixRemoteService create(Throwable throwable) {
return new GoodsFeignHystrixRemoteService() {
@Override
public Result<List<Goods>> feignHystrixList() {
throwable.printStackTrace();
return Result.error(400,"feign调用产品列表服务异常:"+throwable.getMessage());
}
@Override
public Result<Goods> feignHystrixInfo() {
throwable.printStackTrace();
return Result.error(400,"feign调用获取详情服务异常:"+throwable.getMessage());
}
};
}
}