springcloud - hystrix容错

rabbion

Rabbion 是一个客户端负载均衡器(Nginx为服务端负载均衡)。
它赋予了应用一些支配HTTP 与TCP 行为的能力,可以得知,这里的客户端负载平衡也是进程内负载平衡的一种。
它在spring Cloud 生态内是一个不可缺少的组件,少了它,服务便不能横向扩展,这显然是有违云原生12要素的。
此外Feign与Zuul中已经默认集成了Ribbon,在我们的服务之间凡是涉及调用的,都可以集成它并应用,从而使我们调用链具备良好的伸缩性。

Ribbon是Netflix公司开源的一个负载均衡的项目,它属于上述的第二种,是一个客户负载平衡器,运行在客户端上。
他是一个经过了云端测试的IPC库,可以很好地控制HTTP和TCP客户端的一些行为,Feign已经默认使用了Ribbon。
负载均衡
容错
多协议(HTTP,TCP,UDP)支持异步和反应模型
缓存和批处理

Ribbon的负载均衡策略

 andomRule (随机策略):随机选择Server
 RoundRobinRule(轮训策略): 按顺序循环选择 Server
 RetryRule(重试策略):在一起配置时间段内选择Server 不成功,则一直尝试选择一个可用的Server
 BestAusilableRule(最低并发策略):琢个考察Server,如果Server断路器打开,则忽略,在选择其中并发连接最低的Server
 AvailabilityFilteringRule (可用过滤策略):过滤掉一直连接失败并被标记为circuit tripped 的 Server,过滤掉那些高并发连接的Server(active connections 超过配置的网值)
 ResponseTimeWeightedRule (响应时间加权策略): 根据 Server 的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很
    贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间
 ZoneAvoidanceRule (区域权衡策略): 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并且判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

一. 核心思路

现在我们假设一下,服务提供者响应非常缓慢,那么消费者对提供的请求就会被强制等待,直到服务返回。
在高负载场景下,如果不做任何处理,这种问题可能造成所有处理用户的请求的线程都被耗尽,而不能响应用户的进一步请求。
如果是微服务工程,则很多出现服务雪崩效应

什么是雪崩效应:
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间相互调用,在spring cloud可以用RestTemplate+ribbon或feign来调用。
为了保证其高可用,单个服务通常会集群部署,由于网络原因或自身原因,服务不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞。
此时如果大量请求涌入,server容器的线程资源就会被耗尽完毕,导致服务瘫痪,服务与服务之间依赖性,故障会传播,会对整个微服务系统造成灾难的严重后果。
这就是服务故障的雪崩效应.如果不懂,请看下文:
在这里插入图片描述
而此时,A服务的流量波动很大,流量经常突然性增加.那么在这种情况下,就算A服务能扛得住请求,B服务和C服务未必能扛得住这突发的请求.
此时,如果C服务因为扛不住请求,变得不可用,那么B服务的请求也会阻塞,慢慢耗尽B服务的线程资源,B服务就会变得不可用.紧接着,A也会不可用,
这个过程用图来说明,如下:在这里插入图片描述
如图所示:一个服务失败,导致整条链路的服务都失败的情形,我们称之为服务雪崩。

如何解决
1:超时机制
通过网络请求其他服务时,都必须设置超时,征程情况下,一个远程调用一般在几十毫秒被返回了,
当依赖的服务不可用或者因为网络问题,响应时间将会变的很长,而通常情况下,一次远程调用对应了一个线程。
如果响应太慢,那么这个线程得不到释放,而线程对应了系统资源,如果大量的线程得不到释放,并且越积越多.
服务资源就会被耗尽,从而导致资源服务不可用,所以必须为每个请求设置超时时间,如果超时,则释放线程资源.
2: 熔断器模式
试想一下,家庭如果没有断路器,电流过载了(例如:功率过大,电线短路),电路不断开的话,电路就会升温,甚至是烧断电路,起火.
有了断路器之后,当电流过载时,会自动切断点路(跳闸),从而保护了整条电路与家庭的安全,当电流过载的问题解决后,只要将关闭断路器,电路就可以工作了。
同样的道理,当依赖的服务有大量超时时,再让新的请求去访问已经没有太大的意义了,只会无畏的消耗现有的资源。
譬如如果我们设置时间为1秒,如果短时间内有大量请求,在1秒内都得不到响应,就往往意味着异常,此时就没有必要让更多的请求去访问这个服务了,我们应该使用断路器避免资源浪费。
段利器就可以实现快速 失败,如果它在一段时间内侦测到许多类似的错误(比如超时),就会强迫其后续的多个调用快速失败,不再请求所有的依赖的服务,从而方式应用程序不断的尝试执行可能失败的操作,这样因应用程序就可以继续执行而不用等待修正错误,或浪费CPU时间去等待长时间的超时,断路器可以使用因共用程序能够诊断错误是否已修正,如果已经修正,则应用程序再次尝试调用操作。
断路器模式:就像是那些容易导致错误的操作一种代理,就这种代理能够记录最近调用发生错误的次数,然后决定适用于需操作的继续或立即返回错误。

实现断路器的思路:
监控:监控总共请求多少次,有多少次失败,假如失败率为多少,断路器打开
状态 :打开 ,关闭,断开
分流
自我修复(状态的切换)

二. 实现思路(方法级)

因为我们是实现的服务熔断,所以我们的配置需要在消费端配置, 服务端的服务不可用时,消费端走后备方法.

	在消费端<jwxt-learner>配置
	
	pom.xml
	
	<dependency>
	    <groupId>org.springframework.cloud</groupId>
	    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	</dependency> 
	 主启动类
	
	@SpringBootApplication
	@EnableEurekaClient
	@EnableFeignClients
	@EnableHystrix
	public class LearnerApplication {
	    public static void main(String[] args) {
	        SpringApplication.run(LearnerApplication.class,args);
	    }
	} 
	方法级容错回调       
	//获取考试试卷试题列表(用于学生讲解,带答案)
	@RequestMapping(value = "/getAnswerQuestionStudentList",method = RequestMethod.POST,name = "PROFILE")
	@HystrixCommand(fallbackMethod = "getAnswerQuestionStudentListFallBack",commandProperties = {
	        @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"), //开启熔断
	        @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"), //隔离策略: 线程模式,信号量模式
	        @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value="1"),//请求数量达到10个后才计算
	        @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "1"),//错误率
	        @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "1000")//当满足请求数量和  错误率后,会在这个时间内随机拿取一个请求查看是否成功,成功则正常运行,否则继续运行该后备方法
	})
	public Result getAnswerQuestionStudentList(@RequestBody Exam exam){
	    return studentExamService.getAnswerQuestionStudentList(exam);
	}
	
	public Result getAnswerQuestionStudentListFallBack(Exam exam){
	    return new Result(ResultCode.FAIL,"请求错误,服务调用失败,启用后备方法");
	}
    在服务端<jwxt-teacher>中写入错误
	//试卷讲解时的数据集合
	@RequestMapping(value = "/getQuestionExamTeacherList",method = RequestMethod.POST,name = "API-EXAM-EXPLAIN")
	public Result getQuestionExamTeacherList(@RequestBody Exam exam){
	    int i  =  1 / 0;![在这里插入图片描述](https://img-blog.csdnimg.cn/20191010135305231.png)
	    return examService.getQuestionExamList(exam);
	}
    关闭全局异常
	//@ControllerAdvice //controller层的增强器: 捕获controller层抛出的异常
	public class BaseExceptionHandler {
	    //do something ...
	}
	测试访问:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191010135334803.png)

Hystrix的隔离策略两种: 分别是线程隔离和信号量隔离。
THREAD(线程隔离):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中线程数量的限制。
SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受到信号量个数的限制。
Hystrix中默认并且推荐使用线程隔离(THREAD),因为这种方式有一个除网络超时以外的额外保护。
一般来说,只有当调用负载异常高时(例如每个实例每秒调用数百次)才需要信号量隔离,因为这种场景下使用THREAD开销会比较高。信号量隔离一般仅适用于非网络调用的隔离。
可以使用execution.isolation.strategy属性指定隔离策略。
正常情况下,默认为线程隔离, 保持默认即可。
如果发生找不到上下文运行时异常,可考虑将隔离策略设置为SEMAPHORE。

注意: 如果配置了新的后备方法,则必须全部服务重新启动才能显示

在这里插入图片描述

三.实现思路(Feign回调)

   <jwxt-learner>
	application.yml
	feign:
	  client:
	    config:
	      default:
	        connectTimeout: 50000
	        readTimeout: 50000
	        loggerLevel: full
	  hystrix:
	    enabled: true

com.jwxt.clients.fallback.UserClientFallback
@Component
public class UserClientFallback implements UserClient {

//省略其他接口实现....

@Override
public Result getQuestionExamTeacherList(Exam exam) {
    return new Result(ResultCode.FAIL,"启动了userClient实现类的后备方法");
}

}

com.jwxt.clients.UserClient
@FeignClient(name = “JWXT-TEACHER”,fallback = UserClientFallback=.class)
public interface UserClient {
//do something …
}

四.实现思路(Feign回调工厂)

application.yml

配置断路器

hystrix:
  command:
    default:
      circuitBreaker:
        enabled: true   #启动断路器
        requestVolumeThreshold: 10  #请求数达到后才计算
        sleepWindowInMilliseconds: 10000  #休眠时间
        errorThresholdPercentage: 50    #错误率
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000  #设置请求超时时间(默认是一秒) 超时后会走后备方法

com.jwxt.clients.fallback.UserClientFallbackFactory

package com.jwxt.clients.fallback;

import com.jwxt.clients.UserClient;
import com.jwxt.entity.academic.Exam;
import com.jwxt.response.Result;
import com.jwxt.response.ResultCode;
import com.jwxt.vo.QuestionVo;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class UserClientFallbackFactory implements FallbackFactory {

private static final Logger LOGGER = LoggerFactory.getLogger(UserClientFallbackFactory.class);

@Override
public UserClient create(Throwable e) {

    LOGGER.warn("错误服务回调:{}",e.getMessage());

    return new UserClient() {
        
        //省略其他接口实现...
        
        @Override
        public Result getQuestionExamTeacherList(Exam exam) {

            return new Result(ResultCode.FAIL,"启动了回调工厂");
        }
    };
}

}

@FeignClient(name = “JWXT-TEACHER”,fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {
//do something …
}

注意: fallback 与 fallbackFactory 不能同时存在

	方式一: 
	
	application.yml
	feign.hystrix.enabled=false


   方式二:

    通过代码的方式禁用某个客户端
    
	@Configuration
	public class FeignConfiguration {
	    @Bean 
	    @Scope("prototype")
	    public Feign.Builder feignBuilder() {
	        return Feign.builder();
	    }
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值