zoukankan      html  css  js  c++  java
  • 升级微服务架构4:断路器

       断路器是电路中的一个保护电路安全的开关,当电路出现短路时,断路器会自动跳闸,防止出现电路故障。

      一个微服务架构的系统中也需要这种保护装置,当消费者调用某一个服务的时候,如当前的服务有异常,譬如服务已经挂了,这时候就需要断路器来把当前调用的服务断开,Spring Cloud中集成的断路器组件为:Hystrix。如图所示,Hystrix在调用服务失败的情况下会进行回退或者降级处理,比如快速失败、无声失败、返回默认值、自己组装一个返回值、利用远程缓存、主次方式回退等回退类型。

      降级回退相关资料:https://www.jianshu.com/p/3e11ac385c73?from=timeline

      

      以上一章的调用用户服务为例,先实现Java端的再移植到.net core

      1.服务调用设置断路器java版

      在Spring Cloud官方文档搜索断路器:Circuit Breaker

      参考:http://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_circuit_breaker_hystrix_clients

      官方文档示例:

      

      1.1 添加断路器依赖

      断路器是在消费者调用时添加的,首先在orderservice上添加Hystrix依赖  

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

      在启动类上添加@EnableCircuitBreaker注解来启用Hystrix

      1.2 指定调用失败退回方法

      在调用服务类UserService各个方法中添加回退错误的方法,并使用@HystrixCommand注解指定回退的方法 

    @Service
    public class UserService {
    
        @Autowired
        private RestTemplate restTemplate;
    
        private String serviceUrl="http://userservice/user";
    
        @HystrixCommand(fallbackMethod = "getAllError")
        public List<User> getAll() {
            ParameterizedTypeReference<List<User>> responseType = new ParameterizedTypeReference<List<User>>(){};
            ResponseEntity<List<User>> resp = restTemplate.exchange(serviceUrl+"/getall",
                    HttpMethod.GET, null, responseType);
            List<User> list = resp.getBody();
            return list;
        }
    
        @HystrixCommand(fallbackMethod = "getPortError")
        public String getPort(){
            String msg = restTemplate.getForObject(serviceUrl+"/getport", String.class);
            return msg;
        }
    
        public User getByName(String name){
            User user = restTemplate.getForObject(serviceUrl+"/getbyname?name="+name, User.class);
            return user;
        }
    
        //getAll回退方法
        public List<User> getAllError() {
            return null;
        }
        //getPort回退方法
        public String getPortError() {
            return "userservice服务断开,getPort方法调用错误!";
        }
    }

      把userservice服务停掉,调用一下订单服务的获取端口方法,进入了错误方法了,说明已经成功设置回退方法。

      

      启动服务后,调用成功。

      

      

      1.3 设置超时时间

      如果调用一直进入回退方法,可能是Hystrix没设置超时时间,配置下超时时间即可。  

    hystrix:
      command:
        default:
          execution:
            timeout:
              enabled: true
            isolation:
              thread:
                timeoutInMilliseconds: 10000 #设置超时时间 10秒

      

       2.服务调用设置断路器.net core版

       2.1 添加断路器引用

      首先在OrderService项目中添加Steeltoe.CircuitBreaker.HystrixCore引用

      

      2.2 创建Command类来指定退回方法

       在调用用户服务UserService类上继承HystrixCommand<string>

      官方文档:http://steeltoe.io/docs/steeltoe-circuitbreaker/#1-2-8-use-commands

      .net core版比较麻烦的是,不能直接在Service的方法上加特性来声明要回退的方法,而是每个方法要都用一个继承自HystrixCommand<>的泛型方法,泛型类型为方法返回的类型,然后再调用这个类的方法,Java版直接用注解还是方便很多。
      可以参考SteeltoeOSS的例子:https://github.com/SteeltoeOSS/Samples/tree/dev/CircuitBreaker/src/AspDotNetCore/FortuneTeller/Fortune-Teller-UI/Services

       

      两个Command类对应Service里面的两个方法。

      Command类我们按照服务名(去掉后面的Service)+方法名+Command来命名,方便确定是调用的那个方法,譬如获取所有用户的类:UsergetAllCommand。

      

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Steeltoe.CircuitBreaker.Hystrix;
    
    namespace OrderService.Controllers
    {
        public class UsergetAllCommand : HystrixCommand<List<User>>
        {
            private IUserService _userService;
            public UsergetAllCommand(IHystrixCommandOptions options,IUserService userService)
                : base(options)
            {
                _userService = userService;
                IsFallbackUserDefined = true;
            }
            public async Task<List<User>> getAll()
            {
                return await ExecuteAsync();
            }
            protected override async Task<List<User>> RunAsync()
            {
                var result = await _userService.getAll();
                return result;
            }
    
            /// <summary>
            /// 回退方法
            /// </summary>
            /// <returns></returns>
            protected override async Task<List<User>> RunFallbackAsync()
            {
                return null;
            }
        }
    }

      

      同样再创建一个getPort的命令类,然后在Startup类中的ConfigureServices配置HystrixCommand类的注入  

        // 注册使用HystrixCommand类封装UserService方法做断路器的命令类
        services.AddHystrixCommand<UsergetAllCommand>("userservice", Configuration);
        services.AddHystrixCommand<UsergetPortCommand>("userservice", Configuration);

      

      在OrderController中改为使用Command类来调用userservice的方法。  

    [Route("[controller]")]
        [ApiController]
        public class OrderController : ControllerBase
        {
            private readonly IUserService _userService;
    
            private readonly UsergetAllCommand _usergetAllCommand;
    
            private readonly UsergetPortCommand _usergetPortCommand;
            //构造方法来注入实例
            public OrderController(IUserService userService
                ,UsergetAllCommand usergetAllCommand
                ,UsergetPortCommand usergetPortCommand)
            {
                _userService = userService;
                _usergetAllCommand = usergetAllCommand;
                _usergetPortCommand = usergetPortCommand;
            }
    
            [Route("getalluser")]
            [HttpGet]
            public async Task<List<User>> getAll()
            {
                //List<User> list = await _userService.getAll();
                var list =await _usergetAllCommand.getAll();
                return list;
            }
    
            [Route("getuserserviceport")]
            [HttpGet]
            public async Task<string> getUserServicePort()
            {
                //var port = await _userService.getPort();
                var port = await _usergetPortCommand.getPort();
                return port;
            }
    
        }

      停止userservice服务,成功调用回退方法。

      

      启动userservice服务后再刷新,成功获取到数据。

      

      2.3 设置超时时间  

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "spring": {
        "application": {
          "name": "orderservice"
        }
      },
      "eureka": {
        "client": {
          "serviceUrl": "http://localhost:8881/eureka/",
          "shouldRegisterWithEureka": true,
          "shouldFetchRegistry": true
        },
        "instance": {
          "port": 6660
        }
      },
      "hystrix": {
        "command": {
          "default": {
            "execution": {
              "timeout": { "enabled": true },
              "isolation": {
                "thread": { "timeoutInMilliseconds" : 10000 }
              }
            }
          }
        }
      }
    }

      至此断路器已添加完毕。  

  • 相关阅读:
    WPF Step By Step -基础知识介绍
    WPF Step By Step 系列
    设计模式的六大原则
    Java实现二维码生成的方法
    Java 导出Excel
    解析图书 XML
    Maven搭建Spring+SpringMVC+Mybatis+Shiro项目详解
    springboot配置文件的所有属性
    SpringBoot中 application.yml /application.properties常用配置介绍
    Linux 系统目录结构
  • 原文地址:https://www.cnblogs.com/townsend/p/9580371.html
Copyright © 2011-2022 走看看