一、分布式系统面临的问题

  • 在微服务架构体系下,服务间的调用错综复杂,交织成一张大网。如果其中某个节 点突然无法正常工作,则访问它的众多服务都会被卡住,进而有更多服务被卡住,系统 中的线程、CPU、内存等资源有可能被迅速耗尽,最终整个服务体系崩溃。
  • 我们管这样的现象叫服务雪崩。【局部小的问题 导致大的灾难】

    二、Hystrix介绍

  • Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多 依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的 情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

  • “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故 障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应 (FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服 务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延, 乃至雪崩。
  • Hytrix 能够提供服务降级、服务熔断、服务限流、接近实时的监控等方面的功能。

    三、服务熔断机制

  • 熔断机制是应对雪崩效应的一种微服务链路保护机制。 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该 节点微服务的调用,快速响应错误信息。当检测到该节点微服务调用响应正常后恢复调用链 路。在 SpringCloud 框架里熔断机制通过 Hystrix 实现。Hystrix 会监控微服务间调用的状况, 当失败的调用到一定阈值,缺省是 5 秒内 20 次调用失败就会启动熔断机制。熔断机制的注 解是@HystrixCommand。

未命名图片.png

三、熔断-代码部分

熔断指的是provider方的熔断,如果provider方出现的问题,熔断后别的就不在调用这个方法。

1. 在provider工程中添加依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>

2. 在provider主启动类上添加 @EnableCircuitBreaker 注解

  1. /**
  2. * @date: 2021/2/28 15:33
  3. * @author: 易学习
  4. * 下面两个注解功能大致相同,但是这个版本不需要添加
  5. * @EnableDiscoveryClient: 启用发现服务功能,不局限于Eureka注册中心
  6. * @EnableEurekaClient: 启用Eureka客户端功能,必须是Eureka注册中心
  7. *
  8. * @EnableCircuitBreaker: 启用断路器功能【服务熔断】
  9. */
  10. @EnableCircuitBreaker
  11. @SpringBootApplication
  12. public class ApplicationProvider {
  13. public static void main(String[] args) {
  14. SpringApplication.run(ApplicationProvider.class);
  15. }
  16. }

3. 在common 工程中添加一个 ResultEntity ,统一作为AJAX请求和远程服务调用返回值

  1. package com.atguigu.spring.cloud.util;
  2. /**
  3. * 整个项目统一使用这个类型作为Ajax请求或远程方法调用返回响应的数据格式
  4. * @author
  5. *
  6. * @param <T>
  7. */
  8. public class ResultEntity<T> {
  9. public static final String SUCCESS = "SUCCESS";
  10. public static final String FAILED = "FAILED";
  11. public static final String NO_MESSAGE = "NO_MESSAGE";
  12. public static final String NO_DATA = "NO_DATA";
  13. /**
  14. * 操作成功,不需要返回数据
  15. * @return
  16. */
  17. public static ResultEntity<String> successWithoutData() {
  18. return new ResultEntity<String>(SUCCESS, NO_MESSAGE, NO_DATA);
  19. }
  20. /**
  21. * 操作成功,需要返回数据
  22. * @param data
  23. * @return
  24. */
  25. public static <E> ResultEntity<E> successWithData(E data) {
  26. return new ResultEntity<>(SUCCESS, NO_MESSAGE, data);
  27. }
  28. /**
  29. * 操作失败,返回错误消息
  30. * @param message
  31. * @return
  32. */
  33. public static <E> ResultEntity<E> failed(String message) {
  34. return new ResultEntity<>(FAILED, message, null);
  35. }
  36. private String result;
  37. private String message;
  38. private T data;
  39. public ResultEntity() {
  40. }
  41. public ResultEntity(String result, String message, T data) {
  42. super();
  43. this.result = result;
  44. this.message = message;
  45. this.data = data;
  46. }
  47. @Override
  48. public String toString() {
  49. return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
  50. }
  51. public String getResult() {
  52. return result;
  53. }
  54. public void setResult(String result) {
  55. this.result = result;
  56. }
  57. public String getMessage() {
  58. return message;
  59. }
  60. public void setMessage(String message) {
  61. this.message = message;
  62. }
  63. public T getData() {
  64. return data;
  65. }
  66. public void setData(T data) {
  67. this.data = data;
  68. }
  69. }

4. provider工程中的controller方法

  1. /**
  2. * @HystrixCommand 注解通过 fallbackMethod属性指定断路情况下要调用的备用方法
  3. * @param name
  4. * @return
  5. */
  6. @HystrixCommand(fallbackMethod= "getUserBackUp")
  7. @RequestMapping("/provider/get/user")
  8. public ResultEntity<User> getUser(@RequestParam String name){
  9. // 如果这个方法出现 错误/超时 就会去 备用方法 【超时默认为1秒】
  10. return ResultEntity.successWithData(new User(1,"aaa","男"));
  11. }
  12. /**
  13. * 备选方案
  14. * @param name
  15. * @return
  16. */
  17. public ResultEntity<User> getUserBackUp(@RequestParam String name){
  18. return ResultEntity.failed("熔断机制触发!");
  19. }

5.注意:

  • 这只是熔断部分,没有远程调用,所以不用在common的service中写同名接口
  • 浏览器访问的时候直接访问provider的controller【测试】

四、服务降级机制

  • 服务降级处理时在客户端(consumer端)实现完成的,和provider没有关系。
  • 当某个Consumer访问一个provider却迟迟得不到响应时预先设定好一个解决方案,而不是一直等待。

未命名图片.png

1.common工程添加 Hystrix依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  4. </dependency>

2. common工程中需要定义一个工厂类

实现 FallbackFactory 接口【泛型为Common中的远程调用Service】

  1. /**
  2. * @date: 2021/3/5 21:36
  3. * @author: 易学习
  4. * 1.实现Consumer端服务降级的功能
  5. * 2.实现FallbackFactory接口时要传入@FeignClient接口类型
  6. * 3.在create()方法中返回一个@FeignClient注解标注的接口类型的对象,当Provider调用失败后,会执行这个对象的对应方法
  7. */
  8. @Component
  9. public class MyFallBackFactory implements FallbackFactory<UserRemoteService> {
  10. @Override
  11. public UserRemoteService create(Throwable throwable) {
  12. return new UserRemoteService() {
  13. @Override
  14. public ResultEntity<User> getUser(String name) {
  15. return ResultEntity.failed("consumer端降级!!");
  16. }
  17. };
  18. }
  19. }

3. 修改common的远程 调用接口

common工程中原来的远程调用接口 UserRemoteService 的@FeignClients要添加 FallbackFactory属性为自己写的工厂.class
fallbackFactory属性指定provider不可用时提供备用方案的工厂对象
未命名图片.png

4.feign-consumer端启动hystrix

【在配置文件中启动】
  1. feign:
  2. hystrix:
  3. enabled: true