由于对接的系统比较多,为了避免某一个系统接口挂了之后影响整体服务,就想着加一下熔断。选择了hystrix,不过这个有个缺点就是据说好像已经停止迭代了。
首先需要引入jar包,pom依赖如下:
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
之后在启动类上加@EnableHystrix
注解,之后还需要在yaml配置文件上写上配置参数
feign:
hystrix:
#打开hystrix
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000 #设置hystrix的超时时间为1000ms
circuitBreaker:
#在当10秒的时间内,最近10次调用请求,请求错误率超过50%,则触发熔断5秒,期间快速失败,以下都是默认值
requestVolumeThreshold: 10
errorThresholdPercentage: 50
sleepWindowInMilliseconds: 5000
#设置统计的时间窗口值的毫秒值,circuit break 的打开会根据1个rolling window的统计来计算。
#若rolling window被设为10000毫秒,则rolling window会被分成n个buckets,
#每个bucket包含success,failure,timeout,rejection的次数的统计信息。默认10000。
metrics:
rollingStats:
#rolling window大小设置
timeInMilliseconds: 10000
#分的buckets的数量
numBuckets: 10
接下里就是代码里的配置了,根据你的feign的使用方式不同,可以分为两种情况:
情况一:
feign的调用未使用@FeignClient注解,使用方式为配置feignBuilder。
未设置熔断器时,feignBuilder用的是feign类里的builder,如果使用熔断器,则要使用HystrixFeign的builder,源码其实这个类是feign的子类。
然后需要写一个fallback类,该类需要继承你的client接口,
下边这个是我的client接口
public interface ReportClient {
@RequestLine("POST /report/data/report")
@Headers({"Content-Type: application/json", "Accept: application/json"})
JSONObject report(@RequestBody Map<String,Object> params);
@RequestLine("GET /api/hotList/getHotList")
R<List<Long>> getHotIds(@QueryMap Map<String,Object> params);
}
这个则是我的client对应的fallback类:
@Component
public class ReportClientFallBack implements ReportClient{
@Override
public JSONObject report(Map<String, Object> params) {
return new JSONObject();
}
@Override
public R<List<Long>> getHotIds(Map<String, Object> params) {
System.out.println("hystrix success.");
return R.fail("hystrix.");
}
}
重写的方法则是熔断后的默认返回。
最后则是在你的feign工厂类中配置好fallback
@Configuration
public class ReportFactory {
@Value("${URL.reportSystem}")
private String REPORT_URL;
@Resource(name = "report")
private HystrixFeign.Builder feignBuilder;
@Resource
private ReportClientFallBack reportClientFallBack;
@Bean("reportClient")
public ReportClient getReportClient() {
return feignBuilder
.target(ReportClient.class, REPORT_URL,reportClientFallBack);
}
}
本地测试的话,需要把配置文件中的错误次数改为1,同时将调用路径改为错误路径即可,postman测试效果如下(服务的路径改为404路径,但是前端感知不到错误,只是获取的数据源是空,交互友好性提升):
情况二:
feign调用使用的是@FeignClient方式:
同样需要写一个fallback,但是fallback的类不一样:
这是我的fallback:
@Component
@Sl4j
public class AppletPushRemoteServiceFallbackFactory implements FallbackFactory<AppletPushRemoteService> {
@Override
public AppletPushRemoteService create(Throwable throwable) {
return new AppletPushRemoteService() {
@Override
public R<Boolean> baiduBroadcast(BaiduBroadcastMessage message) {
try {
log.error("baiduBroadcast fail message={}", JsonUtil.toJson(message), throwable);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return R.fail("error");
}
@Override
public R<Boolean> baiduSubscribe(BaiduSubscribeMessage message) {
try {
log.error("baiduSubscribe fail message={}", JsonUtil.toJson(message), throwable);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return R.fail("error");
}
@Override
public R<Boolean> wechatSubscribe(WechatSubscribeMessage message) {
try {
log.error("wechatSubscribe fail message={}", JsonUtil.toJson(message), throwable);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return R.fail("error");
}
};
}
}
然后在使用@FeignClient注解时即可指定fallback返回:
@FeignClient(name = "", url = "${}", configuration = CustomFeignBuilder.class, fallbackFactory = AppletPushRemoteServiceFallbackFactory.class)
public interface AppletPushRemoteService {
@PostMapping(value = "/push/baidu/broadcast")
R<Boolean> baiduBroadcast(@RequestBody BaiduBroadcastMessage message);
@PostMapping(value = "/token/wechat")
R<Boolean> baiduSubscribe(@RequestBody BaiduSubscribeMessage message);
@PostMapping(value = "/token/wechat")
R<Boolean> wechatSubscribe(@RequestBody WechatSubscribeMessage message);
}
以上就是Hystrix和feign搭配使用的步骤。