基于Maven的Hystrix 熔断机制

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相关代码


  1. <hystrix.version>1.5.12 </hystrix.version>
  2. <dependency>
  3. <groupId>com.netflix.hystrix </groupId>
  4. <artifactId>hystrix-core </artifactId>
  5. <version>${hystrix.version} </version>
  6. </dependency>


3.2. 编写熔断代码


我是基于AOP注解方式实现熔断方法的


熔断命令的注解类

  1. @Inherited
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.METHOD)
  4. public @interface HystrixCommand {
  5. /**
  6. * 当错误次数达到阈值或者执行超时,直接执行下面代码
  7. * 如果不填fallbackMethod则执行默认熔断方法
  8. * 如果填写fallbackMethod则熔断方法必须在配置注解的同一个类里面,否则抛出MethodNotFoundException
  9. * [熔断方法传参]
  10. * 1. 不传参则直接执行fallbackMethod熔断方法
  11. * 2. 传参则必须和配置注解方法传参类型保持一致, 否则会执行错误
  12. * 参考:HttpHystrixAspect.java
  13. * @return
  14. */
  15. public String fallbackMethod() default "";
  16. }

AOP环绕通知

  1. import java.lang.reflect.Method;
  2. import javax.el.MethodNotFoundException;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.aspectj.lang.ProceedingJoinPoint;
  5. import org.aspectj.lang.annotation.Around;
  6. import org.aspectj.lang.annotation.Aspect;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.stereotype.Component;
  11. import com.netflix.hystrix.HystrixCommand;
  12. import com.netflix.hystrix.HystrixCommandGroupKey;
  13. import com.netflix.hystrix.HystrixCommandKey;
  14. import com.netflix.hystrix.HystrixCommandProperties;
  15. import com.netflix.hystrix.HystrixRequestLog;
  16. import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
  17. @Component
  18. @Aspect
  19. public class HttpHystrixAspect {
  20. private Logger logger = LoggerFactory.getLogger(getClass());
  21. /**
  22. * 对HTTP请求进行AOP操作
  23. */
  24. @Around( "execution (public String com.xxx.ga.service.impl.*.*(..)) && @annotation(hystrixCommand)")
  25. public Object aroundHttpRequest(ProceedingJoinPoint pjp, com.iboxpay.ga.annotation.HystrixCommand hystrixCommand) throws Exception, Throwable{
  26. Object result = null;
  27. // 执行类名
  28. String targetName = pjp.getTarget().getClass().getSimpleName();
  29. MethodSignature signature = (MethodSignature) pjp.getSignature();
  30. // 执行方法名
  31. String methodName = signature.getMethod().getName();
  32. // 初始化熔断器上下文
  33. HystrixRequestContext context = HystrixRequestContext.initializeContext();
  34. try {
  35. result = new HttpHystrix(pjp, targetName, methodName, hystrixCommand).execute();
  36. } finally {
  37. logger.info( "Request => " + HystrixRequestLog.getCurrentRequest().getExecutedCommandsAsString());
  38. context.shutdown();
  39. }
  40. return result;
  41. }
  42. public class HttpHystrix extends HystrixCommand<Object> {
  43. private final ProceedingJoinPoint pjp;
  44. // 类名
  45. private final String className;
  46. // 方法名
  47. private final String methodName;
  48. // 注解
  49. private final com.iboxpay.ga.annotation.HystrixCommand hystrixCommand;
  50. /**
  51. * @param pjp
  52. * @param serviceId 类名+方法名
  53. */
  54. protected HttpHystrix(ProceedingJoinPoint pjp, String className, String methodName, com.iboxpay.ga.annotation.HystrixCommand hystrixCommand) {
  55. // Hystrix uses the command group key to group together commands such as for reporting,
  56. // alerting, dashboards, or team/library ownership.
  57. // 同一个groupKey共用同一个线程池
  58. super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(className))
  59. .andCommandKey(HystrixCommandKey.Factory.asKey(methodName))
  60. // 超时时间
  61. .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds( 5000)));
  62. this.pjp = pjp;
  63. this.className = className;
  64. this.methodName = methodName;
  65. this.hystrixCommand = hystrixCommand;
  66. }
  67. @Override
  68. protected Object run() throws Exception {
  69. try {
  70. return pjp.proceed();
  71. } catch (Throwable e) {
  72. throw new Exception(e);
  73. }
  74. }
  75. /**
  76. * 熔断措施
  77. * 当错误次数达到阈值或者执行超时,直接执行下面代码
  78. */
  79. @Override
  80. protected Object getFallback() {
  81. logger.info( "[{}] 错误次数达到阈值或者执行超时, 进行熔断措施", className + "_" + methodName);
  82. // 熔断方法名称
  83. String fallbackMethod = hystrixCommand.fallbackMethod();
  84. // 未声明了熔断机制,默认熔断方法
  85. if(StringUtils.isEmpty(fallbackMethod)){
  86. return "返回失败";
  87. }
  88. Method methods[] = pjp.getTarget().getClass().getMethods();
  89. Method method = null;
  90. for(Method m : methods){
  91. if(m.getName().equals(fallbackMethod)){
  92. method = m;
  93. break;
  94. }
  95. }
  96. // 未在类中找到申明的fallbackMethod方法
  97. if(method == null){
  98. throw new MethodNotFoundException();
  99. }
  100. // 熔断方法传入参数
  101. Class<?> clazzs[] = method.getParameterTypes();
  102. // 传入参数为空,直接执行方法
  103. if(clazzs.length == 0){
  104. try {
  105. return method.invoke(pjp.getTarget());
  106. } catch (Exception e) {
  107. throw new RuntimeException(e.getMessage());
  108. }
  109. }
  110. // 传入参数不为空,则传入AOP拦截方法参数
  111. try {
  112. return method.invoke(pjp.getTarget(), pjp.getArgs());
  113. } catch (Exception e) {
  114. throw new RuntimeException(e.getMessage());
  115. }
  116. }
  117. }
  118. }

service方法配置HystrixCommand注解

  1. @Override
  2. @HystrixCommand(fallbackMethod = "hiError")
  3. public String testHystrix(int outtimeRate, int runtimeRate) {
  4. /* 模拟数据操作耗时 */
  5. try {
  6. Thread.sleep(( int) (Math.random() * 10) + 2);
  7. } catch (InterruptedException e) {
  8. // do nothing
  9. }
  10. /* 执行失败比率 */
  11. if (Math.random() > ( double) runtimeRate / 100) {
  12. throw new RuntimeException( "运行异常");
  13. }
  14. /* 执行超时比率 */
  15. if (Math.random() > ( double) outtimeRate / 100) {
  16. try {
  17. Thread.sleep(Integer.parseInt(timeOut) + 5);
  18. } catch (Exception e) {
  19. // do nothing
  20. }
  21. }
  22. return "{'status': 'SUCCESS'}";
  23. }
  24. public String hiError(int n, int m) {
  25. logger.info( "熔断措施:hi,sorry,error!");
  26. return "hi,sorry,error!";
  27. }

这里省略掉了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文件增加

  1. <dependency>
  2. <groupId>com.netflix.hystrix </groupId>
  3. <artifactId>hystrix-metrics-event-stream </artifactId>
  4. <version>${hystrix.version} </version>
  5. </dependency>


因为我是基于springboot实现的的,所以直接添加Configuration即可,传统的web项目在web.xml增加对应的servlet和url-mapping就可以了

  1. @Configuration
  2. public class HystrixConfig {
  3. @Bean
  4. public HystrixMetricsStreamServlet hystrixMetricsStreamServlet() {
  5. return new HystrixMetricsStreamServlet();
  6. }
  7. @Bean
  8. public ServletRegistrationBean registration(HystrixMetricsStreamServlet servlet) {
  9. ServletRegistrationBean registrationBean = new ServletRegistrationBean();
  10. registrationBean.setServlet(servlet);
  11. registrationBean.setEnabled( true); //是否启用该registrationBean
  12. registrationBean.addUrlMappings( "/hystrix.stream");
  13. return registrationBean;
  14. }
  15. }

在Hystrix Dashboard管理页面输入路径


就可以看到监控图表了

猜你喜欢

转载自blog.csdn.net/qq_15037231/article/details/80889765
今日推荐