升級微服務架構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 }
          }
        }
      }
    }
  }
}

  至此斷路器已添加完畢。  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM