前言
熔断器(Hystrix)的作用就是为了保护被调用方、自身不会因为某一个服务请求超时或者某个服务不可用而导致整个请求链路挂掉,防止雪崩效应导致这个系统不可用。同时在熔断器的实现中可以很好的实现服务监控,利于运营维护人员进行及时问题排除。这一篇文章我们主要讲如何去使用熔断器,更多的详细文档可以进入github熔断器项目中查看,hystrix开源项目。
使用记录
1.pom添加hystrix依赖
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2.@HystrixCommand(fallbackMethod = "saveOrderFail")进行注解实现熔断
package com.ckmike.order_service.controller;
import com.ckmike.order_service.service.OrderService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* OrderController 简要描述
* TODO:描述该类职责
*
* @author ckmike
* @version 1.0
* @date 18-11-7 下午11:49
* @copyright ckmike
**/
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private StringRedisTemplate redisTemplate;
@RequestMapping("saveforribbon")
@HystrixCommand(fallbackMethod = "saveOrderFail")
public Object saveforRibbon(@RequestParam("user_id") int userId,@RequestParam("product_id") int productId){
return this.orderService.saveForRibbon(userId,productId);
}
@RequestMapping("saveforfeign")
@HystrixCommand(fallbackMethod = "saveOrderFail")
public Object saveforFeign(@RequestParam("user_id") int userId,@RequestParam("product_id") int productId){
return this.orderService.saveForFeign(userId,productId);
}
// 方法参数签名必须与api一致
private Object saveOrderFail(int userId, int productId){
// 监控报警机制
new Thread(()->{
String saveOrderKey = "save-order";
String sendValue = redisTemplate.opsForValue().get(saveOrderKey);
if(StringUtils.isBlank(sendValue)){
// 发送警告消息
System.out.println("紧急消息,用户下单失败,请尽快处理查找原因.");
redisTemplate.opsForValue().set(saveOrderKey, "save-order-fali", 30, TimeUnit.SECONDS);
} else {
System.out.println("已经发送消息,30秒内不可重复发送。");
}
}).start();
Map fallbackResponse = new HashMap();
fallbackResponse.put("code", -100);
fallbackResponse.put("msg","请求人数过多,请稍后再试。");
return fallbackResponse;
}
}
说明:在订单服务调用产品服务出现熔断的处理过程,上面还使用redis作为检查一段时间内是否以及发送监控通知信息,熔断后直接返回兜底数据,防止整个链路出现死等。hystrix主要就是通过@HystrixCommand进行使用。
feign结合Hystrix使用
我们可以通过查看feign的pom可以发现feign已经集合了Hystrix,默认情况下是关闭的,那么如何实现feign上使用Hystrix呢?
1.pom引入Hystrix依赖,这一步是必须要的
2.查看@FeignClient源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.openfeign;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
@AliasFor("name")
String value() default "";
/** @deprecated */
@Deprecated
String serviceId() default "";
@AliasFor("value")
String name() default "";
String qualifier() default "";
String url() default "";
boolean decode404() default false;
Class>[] configuration() default {};
Class> fallback() default void.class;
Class> fallbackFactory() default void.class;
String path() default "";
boolean primary() default true;
}
我们可以看到上面有一个fallback和fallbackFactory属性,其实我们就可以实现一个fallback类去处理FeignClient中fallback的情况。
3.实现ProductService的客户端调用时fallback处理
package com.ckmike.order_service.fallback;
import com.ckmike.order_service.service.ProductClient;
import org.springframework.stereotype.Component;
/**
* ProductServiceFallBack 简要描述
* TODO:描述该类职责
*
* @author ckmike
* @version 1.0
* @date 18-11-23 下午2:04
* @copyright ckmike
**/
@Component
public class ProductServiceFallBack implements ProductClient {
@Override
public String findById(int id) {
System.out.println("产品服务调用失败!!!!!");
System.out.println("调用监控消息组件进行消息发送。");
return null;
}
}
package com.ckmike.order_service.service;
import com.ckmike.order_service.fallback.ProductServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @ClassName ProductClient产品服务客户端
* @Description TODO:描述该接口职责
* @Author ckmike
* @Date 18-11-22 下午4:10
* @Version 1.0
* @Copyright ckmike
**/
@FeignClient(name="product-service", fallback = ProductServiceFallBack.class)
public interface ProductClient {
@GetMapping("/api/v1/product/find")
String findById(@RequestParam(value = "id") int id);
}
4.配置开启feign中hystrix(默认情况下是关闭的)
#feign组件的配置
feign:
#默认是关闭的
hystrix:
enabled: true
client:
config:
default:
connectTimeOut: 2000
readTimeOut: 2000
总结
1.hystrix能够保护调用方和被调用方,防止请求链路因为某一个服务失败而产生雪崩效应。
2.hystrix的隔离熔断策略有线程、信号量两种方式,具体可查看源码
3.熔断器中实现监控是非常有用且非常有必要的,对于运营与维护具有重大意义。
关于SpringCloud相关博客的源代码,在我码云上已经上传,有需要的可以查看SpringCloud项目源代码。