Bootstrap

Feign+Hystrix

写在前面

本篇文章仅作为近日参考其他文章后,自己实践的记录和总结,场景到细节尚有很多不足,有待补充和修正。

OpenFeign

首先了解Fiegn

Feign集成了Ribbon、RestTemplate实现了负载均衡的执行Http调用,只不过对原有的方式(Ribbon+RestTemplate)进行了封装,开发者不必手动使用RestTemplate调服务,而是定义一个接口,在这个接口中标注一个注解即可完成服务调用,这样更加符合面向接口编程的宗旨,简化了开发。

什么是OpenFeign

Feign现在停止迭代了,OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

简单使用

引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类上添加 @EnableFeignClients 注解以启用OpenFeign

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients//*启用Feign
public class ConsumerApplication {

	public static void main(String[] args) {
		new SpringApplicationBuilder(ConsumerApplication.class).web(true).run(args);
	}
}

创建Feign类,这样就为目标服务springcloud-producer提供的接口生成了一个代理客户端,可以直接调用feignClient的方法来访问目标接口。

//value为要调用的服务名(spring.application.name)
@FeignClient(value = "springcloud-producer")
public interface UserClient {

    //和要调用的服务方法描述一致
    @RequestMapping("/queryUsers")
    List<User> queryUsers();
}

Feign的配置方式

与ribbon配置类似,feign也可以通过Configuration类或yaml来实现策略配置。

方式一:
feign有一个默认的配置org.springframework.cloud.netflix.feign.FeignClientsConfiguration.class,我们可以使用@Configuration创建一个配置类,使用@Bean注解来定义同名bean以覆盖默认的配置。

@Configurable
@ConditionalOnClass(Feign.class)
@AutoConfigureAfter(EnableFeignClients.class)
public class FeignAutoConfiguration {

	/**
	 * 使用自定义 feign client 客户端 注意:在使用 SentinelFeign.builder() 来创建 SentinelFeign 客户端作为 Feign
	 * 客户端
	 * @return
	 */
	@Bean
	@Primary
	public Feign.Builder client() {
		return new Feign.Builder();
	}


	/**
	 * 配置 feign 日志打印等级
	 * @return
	 */
	@Bean
	public Logger.Level feignLoggerLevel() {
		return Logger.Level.FULL;
	}
	
}

然后在每个@FeignClient注解中,即可以指定自定义的Configuration

@FeignClient(value = CommonConstant.SERVICE_PRODUCER,configuration = {FeignAutoConfiguration.class})

也可以在@EnableFeignClients注解中将之设置为默认配置。

方式二:
在yaml文件中添加配置

#常规的配置
feign:
  sentinel:
    enabled: true
  okhttp:
    enabled: true
  httpclient:
    enabled: false
  client:
    config:
      default:
        connectTimeout: 100000
        readTimeout: 1000000
        LoggerLevel: FULL
  compression:
    request:
      enabled: true
      min-request-size: 2048
      mime-types: text/xml,application/xml,application/json
    response:
      enabled: true

部分配置详解

  1. 日志级别
    在feign.Logger.class类中内嵌了一个枚举类型Level,包括了四个日志级别

    日志级别说明
    NONE不打印日志
    BASIC只记录请求方法、URL、响应代码以及执行时间等基本信息
    HEADERS打印请求和响应的头部信息
    FULL打印详尽日志

    自定义日志级别首先要在yaml添加配置,以启用DEBUG模式

    logging: 
    	level: 
    		#Feign client的类名或所在包名,这里的值只有DEBUG可选
    		com.ffcs.common.business.org.feign.MyFeign: DEBUG
    

    至于日志级别的配置可以通过方式一提供Bean的方式

    /**
     * 配置 feign 日志打印等级
     * @return
     */
    @Bean
    public Logger.Level feignLoggerLevel() {
    	return Logger.Level.FULL;
    }
    

    或者方式二在yaml中配置

    feign:
      client:
        config:
          #这里default就是全局配置,如果是写服务名称,则是针对某个微服务的配
          default: 
            LoggerLevel: FULL
    
  2. 其他待补充

Hystrix

什么是Hystrix

Hystrix意为“断路器”,就和我们生活中的保险丝,开关一个道理。Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟、异常,引起资源耗尽导致系统不可用的解决方案。主要作用有:

  1. 服务降级
    在访问某个服务接口时,如果发生超时等不可知的异常时,可以断开访问并直接返回一个有好的返回,虽然结果不是正常想要的,但是可以避免异常带来的连锁反应,以此可以保障分布式环境中微服务间相互访问的容错性。

  2. 服务熔断
    在分布式系统中,就是调用一个系统时,在一定时间内,这个服务发生的错误次数达到一定的值时, 我们就打开这个断路器,不让调用过去,而是让他直接去调用降级方法。再过一段时间后,当一次调用时,发现这个服务通了,就将这个断路器改为“半开”状态,让调用一个一个的慢慢过去,如果一直没有发生错误,就将这个断路器关闭,让所有的服务全部通过。

  3. 服务限流
    服务限流就容易理解多了,顾名思义,这是对访问的流量进行限制,就比如上边的场景,我们还可能通过服务限流的方法来解决高并发以及秒杀等问题。主流的限流算法主要有:漏桶算法令牌算法

Hystrix简单使用

引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

在启动类上添加 @EnableCircuitBreaker 注解来开启服务熔断

服务提供端可以使用@HystrixCommand注解来实现

PS: 实际上commandProperties 属性的作用还有待探讨,这里只是简单占个位置

@HystrixCommand(
			fallbackMethod = "getIdError",
			commandProperties = {
					@HystrixProperty(name ="execution.isolation.thread.timeoutInMilliseconds" ,value ="3000" )
			}
	)
	public String getId(String id) {
		return id;
	}

	public String getIdError(String id) {
		return id;
	}

Hystrix常规配置

# hystrix 配置
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE #THREAD|SEMAPHORE
          thread:
            timeoutInMilliseconds:  1200000	#超时时间,单位ms,默认为1000
          semaphore:
            maxConcurrentRequests: 300000	#最大并发请求量,默认10
      circuitBreaker:
        requestVolumeThreshold: 10 #触发熔断的最小请求次数,默认20
        errorThresholdPercentage: 10000 #触发熔断的失败请求最小占比,默认50%
        sleepWindowInMilliseconds:  100000 #触发熔断后的服务休眠时长,休眠结束服务接口将再次启用,默认是5000毫秒
  shareSecurityContext: true

部分内容详解

  1. 资源隔离策略

    隔离的目的限制对共享资源的并发访问量(服务限流

    通过yaml文件配置,路径如下

    hystrix:
      command:
        default:
          execution:
            isolation:
              strategy: SEMAPHORE #THREAD|SEMAPHORE
    

    Hystrix的资源隔离策略有信号量(SEMAPHORE) 和线程池(THREAD)

    1.信号量隔离: 主要是使用一个原子的计数器来记录当前的值,请求来临之前,首先判断计数器的值是否已经达到了设置的最大值,如果没有,则继续运 行,计数器+1;反之,请求处理结束返回后,计数器进行-1,和令牌桶有点像,但是无法处…
    2.线程池隔离: 针对不同的服务设置不同的线程池,这样如果其他服务的线程阻塞的时候不会对其他服务造成影响。

    二者比较

    比较项THREADSEMAPHORE
    线程与调用线程非相同线程与调用线程相同(jetty线程)
    开销排队、调度、上下文开销等无线程切换,开销低
    异步可以是异步,也可以是同步。看调用的方法同步调用,不支持异步
    并发支持支持(最大线程池大小hystrix.threadpool.default.maximumSize)支持(最大信号量上限maxConcurrentRequests)
    是否超时支持,可直接返回不支持,如果阻塞,只能通过调用协议(如:socket超时才能返回)
    是否支持熔断支持,当线程池到达maxSize后,再请求会触发fallback接口进行熔断支持,当信号量达到maxConcurrentRequests后。再请求会触发fallback
    隔离原理每个服务单独用线程池通过信号量的计数器
    资源开销大,大量线程的上下文切换,容易造成机器负载高小,只是个计数器
  2. 其他待补充

Feign+Hystrix

概述

在Hystrix的简单使用中,是Hystrix在服务提供端的使用,而Feign+Hystrix是作为请求端设置的,是最为经典的使用方式。

简单应用

首先是引入依赖

<!--或者openfeign-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-feign</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-hystrix</artifactId>
 </dependency>

feign和hystrix的基础配置可以参考前面的内容,这里重要的是feign启用hystrix

feign:
  hystrix:
    enabled: true

首先需要一个feign client,并指定TestFeignFallbackFactory(服务降级实现类工厂

@FeignClient(contextId = "testFeign1", value = “TEST-APP”, configuration = FeignAutoConfiguration.class, fallbackFactory = TestFeignFallbackFactory.class)
public interface TestFeign {
	@PostMapping("/test/testReq")
	public String testReq(@RequestBody TestVo  testVo);
}

定义FeignFallbackImpl,提供服务降级的方法

@Component
@Slf4j
public class TestFeignFallbackImpl implements TestFeign {

	@Setter
	private Throwable cause;


	@Override
	public String  testReq(TestVo  testVo) {
		log.error("feign接口异常", cause);
		return "feign接口异常";
	}

}

定义FeignFallbackFactory,实现FallbackFactory的create方法来提供服务降级实现类对象的创建

@Component
public class TestFeignFallbackFactory implements FallbackFactory<TestFeign> {
	@Override
	public TestFeign create(Throwable throwable) {
		TestFeignFallbackImpl testFeignFallback = new TestFeignFallbackImpl();
		testFeignFallback .setCause(throwable);
		return testFeignFallback ;
	}
}

其他内容详解

  1. Hysrix Terbined的使用
;