s://github.com/Netflix/Hystrix/wiki
1. 首先介绍一下hystrix是什么?
简单来说,hystrix就是用来容错(潜在的错误、或者致命的错误)的。
2. 那么,不容错会怎么样?
晒下官网的图:
正常情况下访问:每个节点都很正常
如果I挂掉了,执行速度很慢或者执行出现异常,类似于RunTimeException
随着请求不断的往I上面发送,造成服务不可用
wiki原文:
3. 看来容错是很有必要的,接下来看点干货
这里有官网的一个列子:https://github.com/Netflix/Hystrix/tree/master/hystrix-examples,可以下下来看看,很
简单,秒懂!我只是把官网的例子稍作修改。
3.1. 首先在pom.xml里面加入Hystrix相关代码
-
<hystrix.version>1.5.12 </hystrix.version>
-
-
<dependency>
-
<groupId>com.netflix.hystrix </groupId>
-
<artifactId>hystrix-core </artifactId>
-
<version>${hystrix.version} </version>
-
</dependency>
3.2. 编写熔断代码
我是基于AOP注解方式实现熔断方法的
熔断命令的注解类
-
-
-
-
public HystrixCommand {
-
-
/**
-
* 当错误次数达到阈值或者执行超时,直接执行下面代码
-
* 如果不填fallbackMethod则执行默认熔断方法
-
* 如果填写fallbackMethod则熔断方法必须在配置注解的同一个类里面,否则抛出MethodNotFoundException
-
* [熔断方法传参]
-
* 1. 不传参则直接执行fallbackMethod熔断方法
-
* 2. 传参则必须和配置注解方法传参类型保持一致, 否则会执行错误
-
* 参考:HttpHystrixAspect.java
-
* @return
-
*/
-
public String fallbackMethod() default "";
-
-
}
AOP环绕通知
-
import java.lang.reflect.Method;
-
-
import javax.el.MethodNotFoundException;
-
-
import org.apache.commons.lang3.StringUtils;
-
import org.aspectj.lang.ProceedingJoinPoint;
-
import org.aspectj.lang.annotation.Around;
-
import org.aspectj.lang.annotation.Aspect;
-
import org.aspectj.lang.reflect.MethodSignature;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.springframework.stereotype.Component;
-
-
import com.netflix.hystrix.HystrixCommand;
-
import com.netflix.hystrix.HystrixCommandGroupKey;
-
import com.netflix.hystrix.HystrixCommandKey;
-
import com.netflix.hystrix.HystrixCommandProperties;
-
import com.netflix.hystrix.HystrixRequestLog;
-
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
-
-
-
-
public class HttpHystrixAspect {
-
-
private Logger logger = LoggerFactory.getLogger(getClass());
-
-
/**
-
* 对HTTP请求进行AOP操作
-
*/
-
"execution (public String com.xxx.ga.service.impl.*.*(..)) && @annotation(hystrixCommand)")(
-
public Object aroundHttpRequest(ProceedingJoinPoint pjp, com.iboxpay.ga.annotation.HystrixCommand hystrixCommand) throws Exception, Throwable{
-
Object result = null;
-
// 执行类名
-
String targetName = pjp.getTarget().getClass().getSimpleName();
-
MethodSignature signature = (MethodSignature) pjp.getSignature();
-
// 执行方法名
-
String methodName = signature.getMethod().getName();
-
// 初始化熔断器上下文
-
HystrixRequestContext context = HystrixRequestContext.initializeContext();
-
try {
-
result = new HttpHystrix(pjp, targetName, methodName, hystrixCommand).execute();
-
} finally {
-
logger.info( "Request => " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
-
context.shutdown();
-
}
-
return result;
-
}
-
-
public class HttpHystrix extends HystrixCommand<Object> {
-
-
private final ProceedingJoinPoint pjp;
-
-
// 类名
-
private final String className;
-
-
// 方法名
-
private final String methodName;
-
-
// 注解
-
private final com.iboxpay.ga.annotation.HystrixCommand hystrixCommand;
-
-
/**
-
* @param pjp
-
* @param serviceId 类名+方法名
-
*/
-
protected HttpHystrix(ProceedingJoinPoint pjp, String className, String methodName, com.iboxpay.ga.annotation.HystrixCommand hystrixCommand) {
-
// Hystrix uses the command group key to group together commands such as for reporting,
-
// alerting, dashboards, or team/library ownership.
-
// 同一个groupKey共用同一个线程池
-
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(className))
-
.andCommandKey(HystrixCommandKey.Factory.asKey(methodName))
-
// 超时时间
-
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds( 5000)));
-
this.pjp = pjp;
-
this.className = className;
-
this.methodName = methodName;
-
this.hystrixCommand = hystrixCommand;
-
}
-
-
-
protected Object run() throws Exception {
-
try {
-
return pjp.proceed();
-
} catch (Throwable e) {
-
throw new Exception(e);
-
}
-
}
-
-
/**
-
* 熔断措施
-
* 当错误次数达到阈值或者执行超时,直接执行下面代码
-
*/
-
-
protected Object getFallback() {
-
logger.info( "[{}] 错误次数达到阈值或者执行超时, 进行熔断措施", className + "_" + methodName);
-
// 熔断方法名称
-
String fallbackMethod = hystrixCommand.fallbackMethod();
-
// 未声明了熔断机制,默认熔断方法
-
if(StringUtils.isEmpty(fallbackMethod)){
-
return "返回失败";
-
}
-
Method methods[] = pjp.getTarget().getClass().getMethods();
-
Method method = null;
-
for(Method m : methods){
-
if(m.getName().equals(fallbackMethod)){
-
method = m;
-
break;
-
}
-
}
-
// 未在类中找到申明的fallbackMethod方法
-
if(method == null){
-
throw new MethodNotFoundException();
-
}
-
// 熔断方法传入参数
-
Class<?> clazzs[] = method.getParameterTypes();
-
// 传入参数为空,直接执行方法
-
if(clazzs.length == 0){
-
try {
-
return method.invoke(pjp.getTarget());
-
} catch (Exception e) {
-
throw new RuntimeException(e.getMessage());
-
}
-
}
-
// 传入参数不为空,则传入AOP拦截方法参数
-
try {
-
return method.invoke(pjp.getTarget(), pjp.getArgs());
-
} catch (Exception e) {
-
throw new RuntimeException(e.getMessage());
-
}
-
}
-
-
}
-
}
service方法配置HystrixCommand注解
-
-
"hiError")(fallbackMethod =
-
public String testHystrix(int outtimeRate, int runtimeRate) {
-
/* 模拟数据操作耗时 */
-
try {
-
Thread.sleep(( int) (Math.random() * 10) + 2);
-
} catch (InterruptedException e) {
-
// do nothing
-
}
-
/* 执行失败比率 */
-
if (Math.random() > ( double) runtimeRate / 100) {
-
throw new RuntimeException( "运行异常");
-
}
-
/* 执行超时比率 */
-
if (Math.random() > ( double) outtimeRate / 100) {
-
try {
-
Thread.sleep(Integer.parseInt(timeOut) + 5);
-
} catch (Exception e) {
-
// do nothing
-
}
-
}
-
return "{'status': 'SUCCESS'}";
-
}
-
-
public String hiError(int n, int m) {
-
logger.info( "熔断措施:hi,sorry,error!");
-
return "hi,sorry,error!";
-
}
这里省略掉了controller调用service的方法...
至此,Hystrix代码全部结束,testHystrix方法模拟生产环境运行超时、异常情况。
4. 接下来讲一下如何安装hystrix dashboard监控
dashboard下载地址:http://search.maven.org/remotecontent?filepath=com/netflix/hystrix/hystrix-dashboard/1.5.4/hystrix-dashboard-1.5.4.war
下载后直接丢到tomcat或者jetty里面运行就可以了。
运行后访问:http://localhost:7979/hystrix-dashboard/(我的端口号是7979)看到下面界面就说明安装成功了!
接下来pom.xml文件增加
-
<dependency>
-
<groupId>com.netflix.hystrix </groupId>
-
<artifactId>hystrix-metrics-event-stream </artifactId>
-
<version>${hystrix.version} </version>
-
</dependency>
因为我是基于springboot实现的的,所以直接添加Configuration即可,传统的web项目在web.xml增加对应的servlet和url-mapping就可以了
-
-
public class HystrixConfig {
-
-
-
public HystrixMetricsStreamServlet hystrixMetricsStreamServlet() {
-
return new HystrixMetricsStreamServlet();
-
}
-
-
-
public ServletRegistrationBean registration(HystrixMetricsStreamServlet servlet) {
-
ServletRegistrationBean registrationBean = new ServletRegistrationBean();
-
registrationBean.setServlet(servlet);
-
registrationBean.setEnabled( true); //是否启用该registrationBean
-
registrationBean.addUrlMappings( "/hystrix.stream");
-
return registrationBean;
-
}
-
-
}
在Hystrix Dashboard管理页面输入路径
就可以看到监控图表了