微服务-服务熔断/降级-开发实战

学习思路

  1. 名词解释
  2. 代码实践-基于注解、基于Feign
  3. 文末有惊喜

一、名词解释

  1. 服务熔断:在分布式系统中不可避免的会出现服务之间调用异常,一个接口的异常可能导致整个链路异常,服务熔断就是防止这种级联故障的发生,是异常服务快速返回备用数据,顺利完成调用
  2. 服务降级:分布式系统中,面对突发流量,系统可能出现负荷的情况,最终导致服务不可用,这个时候我们需要将一些非核心的服务进行降级(置为不可用),以便节省出更多资源保证核心服务正常运行

相同点:

  1. 熔断和降级都是保证服务在异常情况下还能正常运行,防止系统整体崩溃
  2. 都会导致部分服务短时间不可用

不同点:

  1. 服务熔断:主要用于调用外部接口异常时进行快速返回,防止异常接口成为系统瓶颈,甚至拖垮整个系统
  2. 服务降级:主要是整个系统出现负荷时手动/或预先设置某些非核心服务不可用
  3. 熔断是系统自动判断开启关闭,降级是人为手动或设置开启关闭

二、代码实践-基于注解、基于Feign

1、网关层做熔断降级,具体实现在微服务-gateway-Filter-熔断、限流、统一鉴权

个人建议:不建议在网关实现熔断降级

原因

  1. 网关作为下游业务系统的统一入口,不关心业务,也并不知道哪些是核心/非核心
  2. 服务熔断正常来说需要针对业务去做一些备用数据或快速返回,应该针对业务制定,不应该在网关关心
  3. 网关下调用链上只有其中一个小服务异常,只需要熔断这个小接口即可,如果在网关做可能熔断了整个链路开通默认为下游所有服务不可用

2、单个接口基于注解实现

   1、首先引入jar包

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

    2、在启动类加上注解:@EnableHystrix

    3、在方法上加@HystrixCommand注解

@HystrixCommand(
			groupKey = "usernameGroup",commandKey = "usernameCommand",threadPoolKey = "usernameThread",
			fallbackMethod = "getUsernameFallback",/*ignoreExceptions = Exception.class,*/
			commandProperties = {
					@HystrixProperty(name = "execution.timeout.enabled",value = "true"),
					@HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout",value = "3000")
			},
			threadPoolProperties = {
					@HystrixProperty(name = "coreSize", value = "30"),
					@HystrixProperty(name = "maxQueueSize", value = "101"),
					@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
					@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
					@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
					@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
			}
	)
	@Override
	public String getUsername(@RequestBody OrderDTO orderDTO) {
		log.info("---------------------------=={}", JSON.toJSONString(orderDTO));
		int i=1/0;
		UserDTO userDTO=new UserDTO();
		userDTO.setUserId("userid3");
		userDTO.setUsername("username3");
		String username = productService.getUsername(userDTO);
		log.info("feign2=={}====={}",this.getClass().getSimpleName(),username);
		return username;
	}

注解属性详细见:Configuration · Netflix/Hystrix Wiki · GitHub

这里只介绍几个常用的

  1. commandKey:配置全局唯一标识服务的名称,比如,库存系统有一个获取库存服务,那么就可以为这个服务起一个名字来唯一识别该服务,如果不配置,则默认是@HystrixCommand注解修饰的函数的函数名。
  2. groupKey:一个比较重要的注解,配置全局唯一标识服务分组的名称,比如,库存系统就是一个服务分组。通过设置分组,Hystrix会根据组来组织和统计命令的告、仪表盘等信息。Hystrix命令默认的线程划分也是根据命令组来实现。默认情况下,Hystrix会让相同组名的命令使用同一个线程池,所以我们需要在创建Hystrix命令时为其指定命令组来实现默认的线程池划分。此外,Hystrix还提供了通过设置threadPoolKey来对线程池进行设置。建议最好设置该参数,使用threadPoolKey来控制线程池组。
  3. threadPoolKey:对线程池进行设定,细粒度的配置,相当于对单个服务的线程池信息进行设置,也可多个服务设置同一个threadPoolKey构成线程组。
  4. fallbackMethod:@HystrixCommand注解修饰的函数的回调函数,@HystrixCommand修饰的函数必须和这个回调函数定义在同一个类中,因为定义在了同一个类中,所以fackback method可以是public/private均可。
  5. commandProperties:配置该命令的一些参数,如executionIsolationStrategy配置执行隔离策略,默认是使用线程隔离,此处我们配置为THREAD,即线程池隔离。参见:com.netflix.hystrix.HystrixCommandProperties中各个参数的定义。
  6. threadPoolProperties:线程池相关参数设置,具体可以设置哪些参数请见:com.netflix.hystrix.HystrixThreadPoolProperties
  7. ignoreExceptions:调用服务时,除了HystrixBadRequestException之外,其他@HystrixCommand修饰的函数抛出的异常均会被Hystrix认为命令执行失败而触发服务降级的处理逻辑(调用fallbackMethod指定的回调函数),所以当需要在命令执行中抛出不触发降级的异常时来使用它,通过这个参数指定,哪些异常抛出时不触发降级(不去调用fallbackMethod),而是将异常向上抛出。
  8. observableExecutionMode:定义hystrix observable command的模式;
  9. raiseHystrixExceptions:任何不可忽略的异常都包含在HystrixRuntimeException中;
  10. defaultFallback:默认的回调函数,该函数的函数体不能有入参,返回值类型与@HystrixCommand修饰的函数体的返回值一致。如果指定了fallbackMethod,则fallbackMethod优先级更高。

设置完HystrixCommand注解后,需要编写程序运行异常的fallbackMethod

private String getUsernameFallback(OrderDTO orderDTO,Throwable throwable){
		log.info("fallback====={}==={}",JSON.toJSONString(orderDTO),throwable.getMessage());
		UserDTO userDTO=new UserDTO();
		userDTO.setUserId("userid4");
		userDTO.setUsername("username4");
		return userDTO.getUsername();
	}

这里可以打印异常,返回兜底数据等,当然也可以直接返回空对象,只要调用发有针对性的处理即可

整体思路:

  1. 引入jar
  2. 启动类加注解,启动Hystrixy
  3. 在需要熔断的方法上配置注解
  4. 编写熔断方法的fallbackMethod

3、单个接口基于Feign实现

这里默认认为FeignClient调用环境正常

    1、在FeignClient接口添加fallbackFactory配置

@FeignClient(name = "hystrix-feign2",primary = false,fallbackFactory = HystrixClientFactory.class)
public interface UserService {

	@PostMapping("/feign2/user/get")
	UserDTO getUser(UserDTO userDTO);

}

  2、编写HystrixClientFactory:主要处理服务异常的fallback方法

@Component
@Log4j2
public class HystrixClientFactory implements FallbackFactory<UserService> {
	@Override
	public UserService create(Throwable throwable) {
		log.error("{}{}",throwable.getMessage(),"==============");
		return (userDTO)-> {
			log.info("系统异常=={}",userDTO==null?"userDTO is null":userDTO.toString());
			UserDTO dto=new UserDTO();
			dto.setUsername("error-username");
			dto.setUserId("error-userid");
			return dto;
		};
	}
}

这里需要注意的是要实现FallbackFactory接口,实现create方法,在方法里返回我们要熔断的接口即可,这里只有一个可以直接用lambda表达式即可,多个方法可new接口实现逐个实现方法即可

   3、开启feign.hystrix.enabled=true:这个属性默认是false必须在配置文件显示开启,当然还可以设置超时熔断

hystrix:
  command:
    hystrix-feign2:  #default全局有效,service id指定应用有效
      execution:
        timeout:
          #是否开启超时熔断
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 5000 #断路器超时时间,默认1000ms

feign.hystrix.enabled: true

题外话:至于你需要什么样的熔断策略可以根据系统情况自己配置

比如10秒内错误率达到50%等

最后给个图自己体会

三、服务降级

降级基本都是人工控制,比如系统监控到流量过大触发我们之前的配置,系统某些非核心功能不可用,还可以利用配置中心动态配置开关,我们手动去修改使某些接口进入快速响应

常用配置

mand.default和hystrix.threadpool.default中的default为默认CommandKey

Command Properties
Execution相关的属性的配置:
hystrix.command.default.execution.isolation.strategy 隔离策略,默认是Thread, 可选Thread|Semaphore

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令执行超时时间,默认1000ms

hystrix.command.default.execution.timeout.enabled 执行是否启用超时,默认启用true
hystrix.command.default.execution.isolation.thread.interruptOnTimeout 发生超时是是否中断,默认true
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。
semaphore应该占整个容器(tomcat)的线程池的一小部分。
Fallback相关的属性
这些参数可以应用于Hystrix的THREAD和SEMAPHORE策略

hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用。默认10
hystrix.command.default.fallback.enabled 当执行失败或者请求被拒绝,是否会尝试调用hystrixCommand.getFallback() 。默认true
Circuit Breaker相关的属性
hystrix.command.default.circuitBreaker.enabled 用来跟踪circuit的健康性,如果未达标则让request短路。默认true
hystrix.command.default.circuitBreaker.requestVolumeThreshold 一个rolling window内最小的请求数。如果设为20,那么当一个rolling window的时间内(比如说1个rolling window是10秒)收到19个请求,即使19个请求都失败,也不会触发circuit break。默认20
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 触发短路的时间值,当该值设为5000时,则当触发circuit break后的5000毫秒内都会拒绝request,也就是5000毫秒后才会关闭circuit。默认5000
hystrix.command.default.circuitBreaker.errorThresholdPercentage错误比率阀值,如果错误率>=该值,circuit会被打开,并短路所有请求触发fallback。默认50
hystrix.command.default.circuitBreaker.forceOpen 强制打开熔断器,如果打开这个开关,那么拒绝所有request,默认false
hystrix.command.default.circuitBreaker.forceClosed 强制关闭熔断器 如果这个开关打开,circuit将一直关闭且忽略circuitBreaker.errorThresholdPercentage
Metrics相关参数
hystrix.command.default.metrics.rollingStats.timeInMilliseconds 设置统计的时间窗口值的,毫秒值,circuit break 的打开会根据1个rolling window的统计来计算。若rolling window被设为10000毫秒,则rolling window会被分成n个buckets,每个bucket包含success,failure,timeout,rejection的次数的统计信息。默认10000
hystrix.command.default.metrics.rollingStats.numBuckets 设置一个rolling window被划分的数量,若numBuckets=10,rolling window=10000,那么一个bucket的时间即1秒。必须符合rolling window % numberBuckets == 0。默认10
hystrix.command.default.metrics.rollingPercentile.enabled 执行时是否enable指标的计算和跟踪,默认true
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 设置rolling percentile window的时间,默认60000
hystrix.command.default.metrics.rollingPercentile.numBuckets 设置rolling percentile window的numberBuckets。逻辑同上。默认6
hystrix.command.default.metrics.rollingPercentile.bucketSize 如果bucket size=100,window=10s,若这10s里有500次执行,只有最后100次执行会被统计到bucket里去。增加该值会增加内存开销以及排序的开销。默认100
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 记录health 快照(用来统计成功和错误绿)的间隔,默认500ms
Request Context 相关参数
hystrix.command.default.requestCache.enabled 默认true,需要重载getCacheKey(),返回null时不缓存
hystrix.command.default.requestLog.enabled 记录日志到HystrixRequestLog,默认true

Collapser Properties 相关参数
hystrix.collapser.default.maxRequestsInBatch 单次批处理的最大请求数,达到该数量触发批处理,默认Integer.MAX_VALUE
hystrix.collapser.default.timerDelayInMilliseconds 触发批处理的延迟,也可以为创建批处理的时间+该值,默认10
hystrix.collapser.default.requestCache.enabled 是否对HystrixCollapser.execute() and HystrixCollapser.queue()的cache,默认true

ThreadPool 相关参数
hystrix.threadpool.default.coreSize 并发执行的最大线程数,默认10
hystrix.threadpool.default.maxQueueSize BlockingQueue的最大队列数,当设为-1,会使用SynchronousQueue,值为正时使用LinkedBlcokingQueue。该设置只会在初始化时有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默认-1。
hystrix.threadpool.default.queueSizeRejectionThreshold 即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝。因为maxQueueSize不能被动态修改,这个参数将允许我们动态设置该值。if maxQueueSize == -1,该字段将不起作用
hystrix.threadpool.default.keepAliveTimeMinutes 如果corePoolSize和maxPoolSize设成一样(默认实现)该设置无效。如果通过plugin(https://github.com/Netflix/Hystrix/wiki/Plugins)使用自定义实现,该设置才有用,默认1.
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 线程池统计指标的时间,默认10000
hystrix.threadpool.default.metrics.rollingStats.numBuckets 将rolling window划分为n个buckets,默认10

文内代码地址:spring-cloud-example: 一整套微服务所学

公众号主要记录各种源码、面试题、微服务技术栈,帮忙关注一波,非常感谢

参考文章;

Hystrix的Command属性解读

Spring Cloud @HystrixCommand和@CacheResult注解使用,参数配置

Configuration · Netflix/Hystrix Wiki · GitHub

Home · Netflix/Hystrix Wiki · GitHub

简单谈谈什么是Hystrix,以及SpringCloud的各种超时时间配置效果,和简单谈谈微服务优化

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值