升级微服务架构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依赖   复制代码 org.springframework.cloud spring-cloud-starter-netflix-hystrix 复制代码   在启动类上添加@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 getAll() { ParameterizedTypeReference> responseType = new ParameterizedTypeReference>(){}; ResponseEntity> resp = restTemplate.exchange(serviceUrl+"/getall", HttpMethod.GET, null, responseType); List 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 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   官方文档: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> { private IUserService _userService; public UsergetAllCommand(IHystrixCommandOptions options,IUserService userService) : base(options) { _userService = userService; IsFallbackUserDefined = true; } public async Task> getAll() { return await ExecuteAsync(); } protected override async Task> RunAsync() { var result = await _userService.getAll(); return result; } /// /// 回退方法 /// /// protected override async Task> RunFallbackAsync() { return null; } } } 复制代码      同样再创建一个getPort的命令类,然后在Startup类中的ConfigureServices配置HystrixCommand类的注入   复制代码 // 注册使用HystrixCommand类封装UserService方法做断路器的命令类 services.AddHystrixCommand("userservice", Configuration); services.AddHystrixCommand("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> getAll() { //List list = await _userService.getAll(); var list =await _usergetAllCommand.getAll(); return list; } [Route("getuserserviceport")] [HttpGet] public async Task 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 } } } } } } }https://www.cnblogs.com/townsend/p/9580371.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信