SpringCloud中级篇之Hystrix
程序员文章站
2022-07-02 19:18:28
Hystrix简介借鉴博客:https://blog.csdn.net/qq_40603010/article/details/1091658571. 什么是Hystrix?作用?Hystrix,是一种保护机制,是Netflix开源的一个延迟和容错库。用于隔离访问远程服务、第三方库,防止出现级联失败。官网:https://github.com/Netflix/Hystrix/2. 服务雪崩微服务中,服务间调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,会形成非常复杂的调...
Hystrix简介
- 借鉴博客1:https://blog.csdn.net/qq_40603010/article/details/109165857
- 借鉴博客2:https://blog.csdn.net/qq_43672652/article/details/108453456
1. 什么是Hystrix?作用?
- Hystrix,是一种保护机制,是Netflix开源的一个延迟和容错库。
- 用于隔离访问远程服务、第三方库,防止出现级联失败。
- 官网:https://github.com/Netflix/Hystrix/
2. 服务雪崩
- 微服务中,服务间调用关系错综复杂,一个请求可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路。
- 服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
3. Hystrix中几个重要概念
-
服务降级:
-
服务器忙碌或者网络拥堵时,为了提高用户体验,在用户等待的同时,会返回一个友好提示,fallback(备选方案)
-
服务熔断:
-
应对雪崩效应的一种微服务链路保护机制。
-
当扇出链路的某个微服务出错不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。
-
当检测到该节点微服务调用响应正常后,恢复调用链路。
- 服务限流:
4. Hystrix案例
- 创建服务提供者模块(cloud-provider-hystrix-layment8001)
- pom.xml文件添加依赖
<dependencies>
<!--eureka-client-->
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.krisswen.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
- 编写配置文件
server:
port: 8001
spring:
application:
name: cloud-payment-service #服务名称
eureka:
client:
# 注册进 Eureka 的服务中心
register-with-eureka: true
# 检索 服务中心 的其它服务
fetch-registry: true
service-url:
# 设置与 Eureka Server 交互的地址
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
- 编写启动类
@SpringBootApplication
@EnableDiscoveryClient
public class HystrixPaymentApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixPaymentApplication.class, args);
}
}
- 编写service
@Service
public class PaymentService {
/**
* 可以正常访问的方法
* @param id
* @return
*/
public String paymentInfo_Ok(Integer id){
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_OK,id:" + id;
}
/**
超时访问的方法
*/
public String paymentInfo_Timeout(Integer id){
int interTime = 3;
try{
TimeUnit.SECONDS.sleep(interTime);
}catch (Exception e){
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";
}
}
- 编写controller
@RestController
@Slf4j
public class PaymentController {
@Autowired
PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/hystrix/{id}")
public String paymentInfo_OK(@PathVariable("id")Integer id){
log.info("paymentInfo_OKKKKOKKK");
return paymentService.paymentInfo_Ok(id);
}
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id){
log.info("paymentInfo_timeout");
return paymentService.paymentInfo_Timeout(id);
}
}
- 启动测试类,测试结果
4.1 模拟高并发
- 定义cloud-customer-feign-hystrix-order80
- pom.xml文件中添加依赖
<dependencies>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka-client-->
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.krisswen.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
- 编写配置文件
server:
port: 80
spring:
application:
name: cloud-customer-feign-hystrix-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
- 编写启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 开启Feign客户端
public class HystrixOrderApplication80 {
public static void main(String[] args) {
SpringApplication.run(HystrixOrderApplication80.class, args);
}
}
- 编写feign客户端
@Component
@FeignClient(value = "cloud-payment-service")
public interface OrderService {
@GetMapping("/payment/hystrix/{id}")
public String paymentInfo_OK(@PathVariable("id")Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id);
}
- 编写controller
@RestController
@Slf4j
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("/consumer/payment/hystrix/{id}")
public String paymentInfo_OK(@PathVariable("id")Integer id){
log.info("paymentInfo_OKKKKOKKK");
return orderService.paymentInfo_OK(id);
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id){
log.info("paymentInfo_timeout");
return orderService.paymentInfo_Timeout(id);
}
}
- 测试结果。
4.2 服务降级
4.2.1 局部服务降级( 服务提供方)
- 服务提供方设置局部服务降级
- 服务降级放在消费端,即消费者端,但是提供者端同样适用。
- 提供者设置自身调用超时的峰值,峰值内正常运行,超出峰值需要有兜底的方法处理,作服务降级fallback。
-
局部服务降级步骤:
- 提供方引入Hystrix依赖:
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 提供方service进行设置(对超时方法进行设置)
@Service
public class PaymentService {
/**
* 可以正常访问的方法
* @param id
* @return
*/
public String paymentInfo_Ok(Integer id){
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_OK,id:" + id;
}
/**
超时访问的方法
*/
@HystrixCommand(fallbackMethod = "timeoutHandler",commandProperties = {
//设置峰值,超过 3 秒,就会调用兜底方法,这个时间也可以由feign控制
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_Timeout(Integer id){
int interTime = 5;
try{
TimeUnit.SECONDS.sleep(interTime);
}catch (Exception e){
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " ,paymentInfo_Timeout,id:" + id + "耗时" + interTime + "秒钟";
}
// 定义服务出现异常之后,兜底的方法
public String timeoutHandler(Integer id){
return "服务异常,请重试......";
}
}
- 启动类添加注解
@EnableCircuitBreaker
,开启服务熔断
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker // 开启服务熔断
public class HystrixPaymentApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixPaymentApplication.class, args);
}
}
-
启动服务测试
-
修改服务方中代码(模拟服务出现异常,而不是服务调用超时)
/**
* 超时访问的方法
*
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "timeoutHandler", commandProperties = {
// 设置峰值,超过3秒,调用兜底方法,这个时间可由feign控制
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfo_Timeout(Integer id) {
/* int interTime = 5;
try {
TimeUnit.SECONDS.sleep(interTime);
} catch (Exception e) {
e.printStackTrace();
}*/
int i = 10 / 0; // 模拟服务出现故障
// return "线程池:" + Thread.currentThread().getName() + ",paymentInfo_Timeout,id:" + id + "耗时:" + interTime + "秒";
return "hello";
}
public String timeoutHandler(Integer id) {
return "服务异常,请重试……";
}
- 小结:只要是服务不可用了(调用超时,内部错误),都可以用降级来处理。
4.2.2 局部服务降级(服务消费方设置)
- 步骤:
- 将服务提供方关于服务降级的色湖之全部去掉
- 服务消费方引入hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 在启动类上添加注解
@EnableEircuitBeaker
开启服务熔断
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 开启Feign客户端
@EnableCircuitBreaker // 开启熔断
public class HystrixOrderApplication80 {
public static void main(String[] args) {
SpringApplication.run(HystrixOrderApplication80.class, args);
}
}
- 在controller编写降级逻辑
@RestController
@Slf4j
@SuppressWarnings("all")
public class OrderController {
@Autowired
OrderService orderService;
@GetMapping("/consumer/payment/hystrix/{id}")
public String paymentInfo_OK(@PathVariable("id")Integer id){
log.info("paymentInfo_OKKKKOKKK");
return orderService.paymentInfo_OK(id);
}
@HystrixCommand(fallbackMethod = "handeException", commandProperties = {
//设置峰值,超过 1.5 秒,就会调用兜底方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id")Integer id){
log.info("paymentInfo_timeout");
return orderService.paymentInfo_Timeout(id);
}
public String handeException(Integer id){
return "服务调用异常,请稍后再试.....";
}
}
- 启动类启动测试
- 修改服务提供方代码
@HystrixCommand(fallbackMethod = "timeoutHandler", commandProperties = {
// 设置峰值,超过3秒,调用兜底方法,这个时间可由feign控制
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfo_Timeout(Integer id) {
int i = 10 / 0; // 模拟服务出现故障
return "hello";
}
4.2.3 全局服务降级
- 上面的降级策略,很明显造成了代码的杂乱,提升了耦合度,而且按照这样,每个方法都需要配置一个兜底方法,很繁琐。
- 现在将降级处理方法(兜底方法)做一个全局的配置,设置共有的兜底方法和独享的兜底方法。
- 步骤:
- 服务消费方controller添加全局降级逻辑方法
// 全局服务降级处理方法
public String globalHandler() {
return "这是全局服务降级逻辑的方法……";
}
- 消费方controller上添加一个注解
@DefaultProperties(defaultFallback="globalHandler")
开启全局服务降级 - 消费方controller中修改
paymentInfo_Timeout
方法上的注解@HystrixCommand
/* @HystrixCommand(fallbackMethod = "handlerException",commandProperties = {
// 设置峰值,超过1.5秒,调用兜底方法
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
}) */// 不写自己的 fallbackMethod属性,使用全局默认的
@HystrixCommand // 不写自己的fallbackMethod 属性 使用全局默认
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id) {
log.info("paymentInfo_timeout");
return orderService.paymentInfo_Timeout(id);
}
- 启动测试
小结
- 编写代码中,发现一个有意思的问题:
-
@SpringCloudApplication
注解是个组和注解,其中包含了@SpringBootApplication
@EnableDiscoverCilent
@EnableCircuitBreaker
这三个注解。 - 也就是说,这个使用了这个注解,可以直接替代上述三个注解,简化代码。
- 当然前提是,引入了
hystrix
依赖。
-
@SpringCloudApplication源码
本文地址:https://blog.csdn.net/weixin_44796580/article/details/112850722
下一篇: C# 实现颜色的梯度渐变案例
推荐阅读
-
SpringCloud之熔断监控Hystrix Dashboard的实现
-
springcloud之Hystrix
-
跟我学SpringCloud | 第五篇:熔断监控Hystrix Dashboard和Turbine
-
跟我学SpringCloud | 第四篇:熔断器Hystrix
-
荐 SpringCloud之Config配置中心理论篇
-
springcloud之Config初识篇—客户端批量热加载
-
SpringCloud中级篇之Hystrix
-
SpringCloud之Hystrix【服务降级、服务熔断、服务限流】
-
springcloud实战篇七服务网关之zuul
-
SpringCloud中级(一) ——Hystrix豪猪哥断路器