SpringCloud(三)Hystrix解决雪崩问题-服务降级

雪崩问题

微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路:
在这里插入图片描述
如图,一次业务请求,需要调用A、P、 H、I 四个服务,这四个服务又可能调用其它服务。如果此时,某个服务出现问题。例如微服务 I 发生异常,请求阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞:
服务器支持的线程和并发数有限,请求一直阻塞, 会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
在这里插入图片描述
这就好比,一个汽车生产线,生产不同的汽车,需要使用不同的零件,如果某个零件因为种种原因无法使用,那么就会造成整台车无法装配,陷入等待零件的状态,直到零件到位,才能继续组装。此时如果有很多 个车型都需要这个零件,那么整个工厂都将陷入等待的状态,导致所有生产都陷入瘫疾。一个零件的波及范围不断扩大。

Hystrix解决雪崩问题

Hystrix解决雪崩问题的手段有两个

  • 线程隔离
  • 服务熔断
    在这里插入图片描述
  • Hystrix为每个依赖服务调用分配一个小的线程池, 如果线程池已满调用将被立即拒绝,默认不采用排队加速失败判定时间。
    用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,则会进行降级处理,什么是服务降级?
  • 服务降级:优先保证核心服务,而非核心服务不可用或弱可用。
    用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系統崩溃,至少可以看到一个执行结果(例如返回友好的提示信息:服务器正忙等)。
    服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有响应。
  • 触发Hystix服务降级的情况:
    线程池已满
    请求超时

开启Hystrix

首先在做降级处理之前,应该明确是给那个服务降级,是服务的提供方还是消费方?一般情况是服务的消费方去调用服务的提供方的,服务的提供方出现问题,才会导致服务的消费方出现问题。所以应该是对服务的消费方进行服务的降级处理,例如在调用一个服务时,出现了问题,消费方可以快速的给用户处理响应或一个友好提示。
服务的消费方进行降级处理,不会让服务提供方的的错误影响自己错误,这样自己就不会出现错误了,当然用户在调用服务的消费方时就不会出现错误。

环境准备

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

启动类中,开启@EnableCircuitBreaker功能

//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication

@SpringCloudApplication
public class ConsumerApplication {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){return new RestTemplate();}

    public static void main(String[] args) {
       SpringApplication.run(ConsumerApplication.class);
    }
}

@SpringCloudApplication注解源码

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}

controller改写

编写降级逻辑当目标服务的调用出现故障,我们希望快速失败,给用户一个友好提示。 因此需要提前编写好失败时的降级处理逻辑,要使用@HystixCommond来完成:要注意,因为熔断的降级逻辑方法必须跟正常逻辑方法保证:相同的参数列表和返回值声的。返回User对象没有太大意义,一 般会返回友好提示。所以我们把findById的方法改造为返回String, 反正也是Json数据。这样失败逻辑中返回一个错误说明会比较方便。
@HystrixCommand(fallbackMethod = "findByIdFallback")用来声明一一个降级逻辑的方法当user-service正常提供服务时,访问与以前一致。但是当我们将user-service停机时,会发现页面返回了降级处理

@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "findByIdFallback")
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("{id")
    //失败容错指令,开启服务降级线程隔离的处理,要求这两个方法返回值和参数列表必须相同,因为服务降级的处理逻辑必须和原因的处理保持一致
    //@HystrixCommand(fallbackMethod = "findByIdFallback")
    //不同接口不同方法的超时等待时长应该是不一样的,@HystrixCommand可以设置,配置在类上,则是此类的所有方法生效,要想全局起作用,那就在application.yml中配置
    @HystrixCommand(fallbackMethod = "findByIdFallback",
    commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String findById(@PathVariable("id")Integer id){
        String url="http://user-service/user/findById/"+id;
        String user = restTemplate.getForObject(url, String.class);
        return user;
    }

    public String findByIdFallback(Integer id){
        return "不好意思!服务器正忙!!!!";
    }

    //默认fallback方法,不需要再有参数了
    public String findByIdFallback(){
        return "不好意思!服务器正忙!!!!";
    }
}

application.yaml配置失败容错指令

# 配置全局等待超时时长为3秒,默认是1秒
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000
# 只针对某个服务或方法进行配置等待超时时长,这样就不用在方法中或类中配置
    user-service:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

默认配置如图所示,可以根据这个类进行自定义配置。
在这里插入图片描述
明确:线程隔离是在内部实现,内部已经利用线程池进行了处理,我们只需要去配置他的超时时长,并且开启他的功能即可。

测试

服务提供方user-service线程休眠,模拟线程出现异常。

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User findById(Integer id){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }//模拟等待时长2秒
        return userMapper.selectByPrimaryKey(id);
    }

    public List<User> findAll(){ return userMapper.selectAll();  }
}

在这里插入图片描述
启动服务,一切正常。
在这里插入图片描述
显示一个友好的提示信息。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值