您的位置:首页 > 运维架构 > 网站架构

升级微服务架构4:断路器

2018-09-03 19:31 627 查看
  断路器是电路中的一个保护电路安全的开关,当电路出现短路时,断路器会自动跳闸,防止出现电路故障。

  一个微服务架构的系统中也需要这种保护装置,当消费者调用某一个服务的时候,如当前的服务有异常,譬如服务已经挂了,这时候就需要断路器来把当前调用的服务断开,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 }
}
}
}
}
}
}


  至此断路器已添加完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: