4_hytrix_信号量_线程池


Hystrix

核心特性和原理

  • 熔断: 连续失败次数达到阈值, (有计数器)

    • 恢复:
    • 半请求: 时不时试试, 提供方是否恢复; 例如随机策略, 按时间间隔策略; 重试成功后, 重置标志位/计数器
    • 相互之间不通知, 其实也不能通知, 例如: 会引发广播风暴
  • 降级: 返回差一点的响应; 写mq; 备用方案;

  • 隔离(线程隔离): 线程数/池: 控制到具体url 的线程个数(1:46); map<url, thread_count>;

    • 这里的线程 和 tomcat线程池中的是一个list 吗? 还是单独 http请求服务的线程?
    • Tomcat 线程数是整个应用的个数;
  • Hystrix实现: 代理

  • 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。

使用

  • Hystrix 可以脱离spring-cloud
  • 依赖: 2:00, 在consumer 中配置:
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  • 使用:

    • 继承 HystrixCommand;
    • 重写 run, getFallback, 方法
    • 还要重写一个 构造方法
  • hystrix有两种执行模式:

    • execute(): 以同步阻塞方式执行run(),调用execute()后,hystrix先创建一个新线程运行run(),接着调用程序要在execute()调用处一直阻塞着,直到run()运行完成;
    • queue(): 以同步非阻塞方式执行run(),调用queue()就直接返回一个Future对象,同时hystrix创建一个新线程运行run(),调用程序通过Future.get()拿到run()的返回结果;

单独使用

package com.go.cn.test;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class HystrixTest extends HystrixCommand {

    private static Logger logger = LoggerFactory.getLogger(HystrixCommand.class);

    protected HystrixTest(HystrixCommandGroupKey group) {
        super(group);
    }


    public static void main(String[] args) {
        // 阻塞方式
       /* HystrixTest hystrixTest = new HystrixTest(HystrixCommandGroupKey.Factory.asKey("ext"));
        logger.info("==>>: result={}", hystrixTest.execute());*/

        // 非阻塞方式
        Future<String> futureResult = new HystrixTest(HystrixCommandGroupKey.Factory.asKey("ext")).queue();
        String result = "";
        try {
            result = futureResult.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        logger.info("==>>: result={}", result);
    }

    @Override
    protected Object run() throws Exception {
        System.out.println("执行逻辑");
        int i = 1 / 0;
        return String.valueOf(i);
    }

    @Override
    protected Object getFallback() {
        return "getFallback:getFallback";
    }
}

--- 执行结果 ---
15:16:41.825 [main] INFO com.netflix.hystrix.HystrixCommand - result=getFallback:getFallback    
  • 图形化: ${prefix}/hystrix

整合 Feign

  • 也有两种:1-指定 Fallback 类;2-指定 FallbackFactory 工厂类;

  • 在调用方的 类上不能加 @RequestMapping(), 需要单独写道每个方法上; 就是路径前缀需要重复写;

  • 配置:

feign:
  hystrix:
    enabled: true
  • service 和 controller: 1-指定 Fallback 类;
---service---
package com.go.cn.service;

import com.go.cn.conf.HystrixFeignBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

//@RequestMapping("/hystrix") // feign 有 fallback 属性时这个注解要去掉
//@FeignClient(name = "provider", configuration = FeignAuthConfiguration.class)
@FeignClient(name = "provider", contextId = "hystrix", fallback = HystrixFeignBack.class)
public interface HystrixFeignService {

    @GetMapping("/hystrix/feign_hystrix")
    String getPort();

}
--- 降级类 需要实现对应的Service接口 ---
package com.go.cn.service;

import org.springframework.stereotype.Component;

@Component
public class HystrixFeignBack implements HystrixFeignService {

    /**
     * 方法名和 feign 调用时的方法名一致
     */
    @Override
	public String getPort() {
		return "getPort:fail_back";
	}
}
--- controller ---
package com.go.cn.controller;

import com.go.cn.service.HystrixFeignService;
import com.go.cn.service.HystrixXRestTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HystrixController {
    private HystrixXRestTemplateService hystrixService;
    private HystrixFeignService hystrixFeignService;

    @Autowired
    public void setFeignApiService(HystrixXRestTemplateService hystrixService) {
        this.hystrixService = hystrixService;
    }
    @Autowired
    public void setHystrixFeignService(HystrixFeignService hystrixFeignService) {
        this.hystrixFeignService = hystrixFeignService;
    }

    @GetMapping("/restTemplate_hystrix")
    public String getPort(){
        return hystrixService.runFun();
    }

    @GetMapping("/feign_hystrix")
    public String feign_hystrix(){
        return hystrixFeignService.getPort();
    }
}

  • 注意 contextId = "hystrix" 配置后,之前配置的认证可能会失效,因为服务名变了;暂时的解决方式是去掉认证。//todo

  • 2-指定 FallbackFactory 工厂类: create(Throwable cause) 方法中传入了具体的异常类信息,所以可以使用FallbackFactory 定义具体不同的降级信息;

  • Factory 类 和 service 的调整:

package com.go.cn.service;

import feign.FeignException;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class HystrixFeignFallbackFactory implements FallbackFactory<HystrixFeignService> {

	@Override
	public HystrixFeignService create(Throwable cause) {
		return new HystrixFeignService() {
            @Override
            public String getPort() {
                if(cause instanceof FeignException.InternalServerError) {
                    return "远程服务报错";
                }else if(cause instanceof RuntimeException) {
                    return "请求时异常:" + cause;
                }else {
                    return "其他情况";
                }
            }
        };
	}

}
--- service---
package com.go.cn.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

//@RequestMapping("/hystrix") // feign 有 fallback 属性时这个注解要去掉
//@FeignClient(name = "provider", configuration = FeignAuthConfiguration.class)
//@FeignClient(name = "provider", contextId = "hystrix", fallback = HystrixFeignBack.class, fallbackFactory=HystrixFeignFallbackFactory.class)
@FeignClient(name = "provider", contextId = "hystrix", fallbackFactory=HystrixFeignFallbackFactory.class)
public interface HystrixFeignService {

    @GetMapping("/hystrix/feign_hystrix")
    String getPort();

}

整合RestTemplate

  • 加好依赖
  • 启动类加:@EnableCircuitBreaker
  • service 和 controller:
---service---
package com.go.cn.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Service
public class HystrixXRestTemplateService {


    @Autowired
    @Qualifier("restTemplate")
    RestTemplate template;
	
	@HystrixCommand(defaultFallback = "fail")
	public String runFun() {
		String url ="http://provider/restTemplate_hystrix";
        return template.getForObject(url, String.class);
	}

	public String fail() {
		return "rest_template:fail";
	}

}
--- controller ---
package com.go.cn.controller;

import com.go.cn.service.HystrixXRestTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HystrixController {
    private HystrixXRestTemplateService hystrixService;

    @Autowired
    public void setFeignApiService(HystrixXRestTemplateService hystrixService) {
        this.hystrixService = hystrixService;
    }

    @GetMapping("/restTemplate_hystrix")
    public String getPort(){
        return hystrixService.runFun();
    }
}

信号量与线程隔离

线程池隔离

  • 针对每个不同的服务维护一个线程池;
  • 不同服务互不影响; 不会由于某个服务调用导致当前服务卡死;
  • 缺点就是, 开心稍微有点大;
  • 官方推荐此方案:
    • 可以做失败策略;
    • 异常的隔离;
    • 异步请求, 解放 worker 线程池的阻塞;

信号量隔离

  • 根据 URI 设置信号量; 拿不到信号量 直接 fallback;
  • 更加轻量级;

常用配置

hystrix:
  command:
    default:
      execution:
        isolation:
          semaphore:
          # 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。
          # 如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,
          # 但选用semaphore时每次执行的代码量比较小且执行速度快(ms级别),否则的话应该用thread。
            maxConcurrentRequests: 20
            # 隔离策略,默认是Thread, 可选Thread|Semaphore
            # - 通过semaphore count来限制并发请求数,适用于无网络的高并发请求,semaphore应该占整个容器(tomcat)的线程池的一小部分;
            #  通过线程数量来限制并发请求数,可以提供额外的保护,但有一定的延迟。一般用于网络调用
          strategy: Semaphore  # SEMAPHORE
          thread:
            # 发生超时是是否中断,默认 true
            interruptOnTimeout: true
            # 命令执行超时时间,默认1000ms
            timeoutInMilliseconds: 1000
        # 执行是否启用超时,默认启用 true    
        timeout:
          enabled: true
  • 使用信号量, 配置:
    • 配置文件:hystrix.command.default.execution.isolation.strategy=SEMAPHORE

hystrix 使用dashboard

  • 可以是一个独立项目,也可以在某个项目里;
  • 添加依赖:
<!-- 独立服务中需要的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- 被监控的服务需要的依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 主类:@EnableHystrixDashboard
  • 被监控的服务中增加配置类:
import com.netflix.hystrix.Hystrix;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OrderActuator {

    @Bean
    public ServletRegistrationBean getServletRegistrationBean(){

        HystrixMetricsStreamServlet mss = new HystrixMetricsStreamServlet();

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(mss);

        servletRegistrationBean.setName("servletRegistrationBean");
        servletRegistrationBean.setLoadOnStartup(1);
        servletRegistrationBean.addUrlMappings("/hystrix.stream");
        return servletRegistrationBean;
    }

}
  • 图形化查看: http://service_ip:port/hystirx;在其中输入框中输入 http://被监控ip:port/hystrix.stream
  • 查看 hystrix.stream: http://ip:port/actuator/hystrix.stream
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值