基于Maven的Hystrix 熔断机制

GitHub关于hystrix文档:https://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注解方式实现熔断方法的


熔断命令的注解类

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface 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;

@Component
@Aspect
public class HttpHystrixAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 对HTTP请求进行AOP操作
     */
    @Around("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;
        }
        
        @Override
        protected Object run() throws Exception {
            try {
                return pjp.proceed();
            } catch (Throwable e) {
                throw new Exception(e);
            }
        }

        /**
         * 熔断措施
         * 当错误次数达到阈值或者执行超时,直接执行下面代码
         */
        @Override
        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注解

@Override
    @HystrixCommand(fallbackMethod = "hiError")
    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就可以了

@Configuration
public class HystrixConfig {

    @Bean
    public HystrixMetricsStreamServlet hystrixMetricsStreamServlet() {
        return new HystrixMetricsStreamServlet();
    }

    @Bean
    public ServletRegistrationBean registration(HystrixMetricsStreamServlet servlet) {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean();
        registrationBean.setServlet(servlet);
        registrationBean.setEnabled(true); //是否启用该registrationBean
        registrationBean.addUrlMappings("/hystrix.stream");
        return registrationBean;
    }

}

在Hystrix Dashboard管理页面输入路径


就可以看到监控图表了





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenFeign是一个用于构建基于HTTP的RESTful服务客户端的Java库,它是Spring Cloud中的一部分。熔断是一种服务保护机制,当某个服务出现故障或响应超时时,熔断器可以快速失败并避免对该服务的连续调用。在OpenFeign中,可以使用Hystrix来实现熔断功能。 要在OpenFeign中实现熔断,需要进行以下步骤: 1. 添加HystrixHystrix Feign依赖。在Maven项目中,可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 在启动类上添加@EnableFeignClients和@EnableCircuitBreaker注解,启用Feign和熔断功能: ```java @SpringBootApplication @EnableFeignClients @EnableCircuitBreaker public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` 3. 在需要调用远程服务的Feign客户端接口上添加@FeignClient注解,并使用fallback属性指定熔断时的备选方案: ```java FeignClient(name = "your-service", fallback = YourServiceFallback.class) public interface YourServiceClient { // 定义远程服务的接口方法 } @Component public class YourServiceFallback implements YourServiceClient { // 实现熔断时的备选方案 } ``` 4. 配置Hystrix的相关属性,可以在application.properties或application.yml文件中添加以下配置: ```yaml hystrix: command: default: execution.isolation.thread.timeoutInMilliseconds: 5000 # 设置超时时间 ``` 通过以上步骤,就可以在OpenFeign中实现熔断保护机制。当远程服务调用失败或超时时,将会触发熔断器,执行备选方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值