Java 杂谈互联网科技

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

2018-09-03  本文已影响0人  像程序一样思考

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

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

org.springframework.cloudspring-cloud-starter-netflix-hystrix

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

1.2 指定调用失败退回方法

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

@ServicepublicclassUserService{@AutowiredprivateRestTemplate restTemplate;privateString serviceUrl="http://userservice/user";@HystrixCommand(fallbackMethod ="getAllError")publicList getAll() {        ParameterizedTypeReference> responseType = new ParameterizedTypeReference>(){};        ResponseEntity> resp = restTemplate.exchange(serviceUrl+"/getall",                HttpMethod.GET,null, responseType);        List list = resp.getBody();returnlist;    }@HystrixCommand(fallbackMethod ="getPortError")publicString getPort(){        String msg = restTemplate.getForObject(serviceUrl+"/getport", String.class);returnmsg;    }publicUser getByName(String name){        User user = restTemplate.getForObject(serviceUrl+"/getbyname?name="+name, User.class);returnuser;    }//getAll回退方法publicList getAllError() {returnnull;    }//getPort回退方法publicString 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

官方文档: 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{publicclassUsergetAllCommand:HystrixCommand>{privateIUserService _userService;publicUsergetAllCommand(IHystrixCommandOptions options,IUserService userService)            : base(options)        {            _userService = userService;            IsFallbackUserDefined =true;        }publicasync Task> getAll()        {returnawait ExecuteAsync();        }protectedoverrideasync Task> RunAsync()        {varresult = await _userService.getAll();returnresult;        }/// /// 回退方法/// /// protectedoverrideasync Task> RunFallbackAsync()        {returnnull;        }    }}

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

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

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

[Route("[controller]")]    [ApiController]publicclassOrderController:ControllerBase{privatereadonlyIUserService _userService;privatereadonlyUsergetAllCommand _usergetAllCommand;privatereadonlyUsergetPortCommand _usergetPortCommand;//构造方法来注入实例publicOrderController(IUserService userService

            ,UsergetAllCommand usergetAllCommand

            ,UsergetPortCommand usergetPortCommand){            _userService = userService;            _usergetAllCommand = usergetAllCommand;            _usergetPortCommand = usergetPortCommand;        }        [Route("getalluser")]        [HttpGet]publicasyncTask> getAll()        {//List list = await _userService.getAll();varlist =await_usergetAllCommand.getAll();returnlist;        }        [Route("getuserserviceport")]        [HttpGet]publicasyncTaskgetUserServicePort(){//var port = await _userService.getPort();varport =await_usergetPortCommand.getPort();returnport;        }    }

停止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}          }        }      }    }  }}

至此断路器已添加完毕

上一篇 下一篇

猜你喜欢

热点阅读