谈谈Circuit Breaker在.NET Core中的简单应用

http://www.cnblogs.com/catcher1994/p/8975192.html

前言

由于微服务的盛行,不少公司都将原来细粒度比较大的服务拆分成多个小的服务,让每个小服务做好自己的事即可。

经过拆分之后,就避免不了服务之间的相互调用问题!如果调用没有处理好,就有可能造成整个系统的瘫痪,好比说其中一些基础服务出现了故障,那么用到这些基础服务的地方都是要做一定的处理的,不能让它们出现大面积的瘫痪!!!

正常情况下的解决方案就要对服务进行熔断处理,不能因为提供方出现了问题就让调用方也废了。

熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施。

对于这个问题,Steeltoe的Circuit Breaker是一个不错的选择。本文的示例代码也是基于它的。

Steeltoe的Circuit Breaker

Steeltoe是什么呢?Steeltoe可以说是构建微服务的一个解决方案吧。具体的可以访问它的官网:

http://steeltoe.io/

回归正题,先来看看官方对Circuit Breaker的描述:

What do you do when a service you depend on stops responding? Circuit breakers enable you to bypass a failing service, allowing it time to recover, and preventing your users from seeing nasty error messages. Steeltoe includes a .NET implementation of Netflix Hystrix, a proven circuit breaker implementation with rich metrics and monitoring features.

不难发现,Circuit Breaker可以让我们很好的处理失败的服务。它也包含了对Netflix Hystrix的.NET(Core)实现。

关于熔断机制,有个非常经典的图(这里直接拿了官方文档的图),核心描绘的就是三种状态之间的变化关系。

说了那么多,下面还是来看个简单的例子来略微深入理解一下吧。

注:服务发现和服务注册不是本文的重点,所以这里不会使用Steeltoe相应的功能。

简单例子

先定义一个简单的订单服务,这个服务很简单,就一个返回直接返回对应订单号的接口,这里用默认的ASP.NET Core Web API项目做一下调整就好了。

[Route("api/[controller]")]

public class ValuesController : Controller

{

// GET api/values/123

[HttpGet("{id}")]

public string Get(string id)

{

return $"order-{id}";

}

}

再来一个新服务去调用上面的订单服务。

先抛开熔断相关的,定义一个用于访问订单服务的Service接口和实现。

public interface IOrderService

{

Task GetOrderDetailsAsync(string orderId);

}

public class OrderService : IOrderService

{

public async Task GetOrderDetailsAsync(string orderId)

{

using (HttpClient client = new HttpClient())

{

return await client.GetStringAsync($"http://localhost:9999/api/values/{orderId}");

}

}

}

比较简单,就是发起HTTP请求到订单服务,拿一下返回的结果。

忽略熔断的话,现在已经可以通过这个OrderService去拿到结果了。

[HttpGet]

public async Task Get([FromServices] Services.IOrderService service, string id = "0")

{

return await service.GetOrderDetailsAsync(id);

}

结果如下:

这是最最最最理想的情况!如果我们把订单服务停了,会发生什么事呢?

十分尴尬,这个订单服务的调用方也废了。

当然,try-catch也是可以帮我们处理这个尴尬的问题,但这并不是我们想要的结果啊!

下面来看看引入Circuit Breaker之后如何略微优雅一点去处理这个问题。

定义一个GetOrderDetailsHystrixCommand,让它继承HystrixCommand。

public class GetOrderDetailsHystrixCommand : HystrixCommand

{

private readonly IOrderService _service;

private readonly ILogger _logger;

private string _orderId;

public GetOrderDetailsHystrixCommand(
IHystrixCommandOptions options,
IOrderService service,
ILogger<GetOrderDetailsHystrixCommand> logger
) : base(options)
{
this._service = service;
this._logger = logger;
this.IsFallbackUserDefined = true;
} public async Task<string> GetOrderDetailsAsync(string orderId)
{
_orderId = orderId;
return await ExecuteAsync();
} protected override async Task<string> RunAsync()
{
var result = await _service.GetOrderDetailsAsync(_orderId);
_logger.LogInformation("Get the result : {0}", result);
return result;
} protected override async Task<string> RunFallbackAsync()
{
//断路器已经打开
if (!this._circuitBreaker.AllowRequest)
{
return await Task.FromResult("Please wait for sometimes");
} _logger.LogInformation($"RunFallback");
return await Task.FromResult<string>($"RunFallbackAsync---OrderId={_orderId}");
}

}

这里有几个地方要注意:

构造函数一定要有IHystrixCommandOptions这个参数

RunAsync是真正执行调用的地方

RunFallbackAsync是由于某些原因不能拿到返回结果时会执行的地方,所谓的优雅降级。

接下来要做的是在Startup中进行注册。

public void ConfigureServices(IServiceCollection services)

{

services.AddSingleton<IOrderService, OrderService>();

services.AddHystrixCommand("Order", Configuration);

services.AddMvc();

}

可以看到,在添加熔断命令的时候,还用到了Configuration这个参数,这就说明,我们还少了配置!!

配置是放到appsettings.json里面的,下面来看一下要怎么配置:

{

"hystrix": {

"command": {

"default": {

"circuitBreaker": {

//是否启用,默认是true

"enabled": true,

//在指定时间窗口内,熔断触发的最小个数

"requestVolumeThreshold": 5,

//熔断多少时间后去尝试请求

"sleepWindowInMilliseconds": 5000,

//失败率达到多少百分比后熔断

"errorThresholdPercentage": 50,

//是否强制开启熔断

"forceOpen": false,

//是否强制关闭熔断

"forceClosed": false

},

//是否启用fallback

"fallback": {

"enabled": true

}

}

}

}

}

需要添加一个名字为hystrix的节点,里面的command节点才是我们要关注的地方!

default,是默认的配置,针对所有的Command!如果说有某个特定的Command要单独配置,可以在command下面添加相应的命令节点即可。

其他配置项,都已经用注释的方式解释了。

下面这张动图模拟了订单服务从可用->不可用->可用的情形。

除了服务不可用,可能还有一种情况发生的概率会比较大,超时!

举个例子,有一个服务平常都是响应很快,突然有一段时间不知道什么原因,处理请求的速度慢了很多,这段时间内经常出现客户端等待很长的时间,甚至超时了。

当遇到这种情况的时候,一般都会设置一个超时时间,只要在这个时间内没有响应就认为是超时了!

可以通过下面的配置来完成超时的配置:

{

"hystrix": {

"command": {

"default": {

"execution": {

"timeout": {

"enabled": true

},

"isolation": {

"strategy": "THREAD",

"thread": {

//超时时间

"timeoutInMilliseconds": 1000

}

}

},

}

}

}

}

总结

这里也只是介绍了几个比较常用和简单的功能,它还可以合并多个请求,缓存请求等诸多实用的功能。总体来说,Steeltoe的熔断功能,用起来还算是比较简单,也比较灵活。

更多配置和说明可以参考官方文档。

本文的示例代码:

CircuitBreakerDemo

Steeltoe的更多相关文章

  1. .net framework 4.5 +steeltoe+ springcloud 实现服务注册功能

    首先得先了解并熟悉一下springcloud,并手动去搭建一个服务中心,具体可度娘教程. 如果是.net core的话,实现注册也是没有问题的,网上教程很多,可自行度娘. 最难的就是基于Framewo ...

  2. .NET Core微服务之基于Steeltoe使用Eureka实现服务注册与发现

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  3. .NET Core微服务之基于Steeltoe集成Zuul实现统一API网关

    Tip: 此篇已加入.NET Core微服务基础系列文章索引,本篇接上一篇<基于Steeltoe使用Eureka实现服务注册与发现>,所演示的示例也是基于上一篇的基础上而扩展的. => ...

  4. .NET Core微服务之基于Steeltoe使用Hystrix熔断保护与监控

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  5. .NET Core微服务之基于Steeltoe使用Spring Cloud Config统一管理配置

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  6. .NET Core微服务之基于Steeltoe使用Zipkin实现分布式追踪

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 =>  Steeltoe目录快速导航: 1. 基于Steeltoe使用Spring Cloud Eureka 2. 基于Steelt ...

  7. .NET Core 微服务架构 Steeltoe 使用(基于 Spring Cloud)

    阅读目录: 1. Spring Cloud Eureka 注册服务及调用 2. Spring Cloud Hystrix 断路器 3. Spring Cloud Hystrix 指标监控 4. Spr ...

  8. HttpClientFactory与Steeltoe结合来完成服务发现

    前言 上一篇说了一下用HttpClientFactory实现了简单的熔断降级. 这篇就来简单说说用HttpClientFactory来实现服务发现.由于标题已经好明显的说了Steeltoe 因此这里会 ...

  9. Steeltoe之Distributed Tracing篇

    Steeltoe里的分布式追踪功能与Spring Cloud Sleuth一样,支持在日志中记录追踪数据,或者上传到远端的服务,比如Zipkin. Logging 在Steeltoe中使用日志时需要引 ...

  10. .net framework 4.5 +steeltoe+ springcloud(二) 实现服务发现与调用功能

    首先,写一个简单的可被调用的服务注册到服务中心,我们这命名为java-service,用的是IDEA创建一个spring boot项目,选择spring client类型. 修改application ...

随机推荐

  1. 九度oj 1003 A+B 2010年浙江大学计算机及软件工程研究生机试真题

    题目1003:A+B 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:12812 解决:5345 题目描述: 给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号",&qu ...

  2. 【curl】Linux下命令行curl详解

    在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具.它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具. 语法:# c ...

  3. How to push master to QA branch in GIT

    1.  git branch -d QA2.  git branch QA master3.  git checkout QA4.  git push origin QA(if push error, ...

  4. PHP学习8——图像处理

    主要内容: 加载GD库 创建图像 绘制点,线,矩形,多边形,椭圆,弧线 绘制文字 通过GD库生成验证码 其实吧,学习图像方法的最大作用,好像就是为了制作验证码. 所以此专题,不如叫做制作验证码. 1. ...

  5. php数组操作,js数组操作

    俩语言一块儿学老混.整理一下. php: 1.声明: 1)$arr1 = array('key1' => 'value1', 'key2' => 'value2' ...);//关联数组, ...

  6. 1.http请求编程-->基础原理

    一.技术分析 打开网页,不管我们请求的是静态资源还是动态资源,IIS都会根据ISAPI(微软和Process软件公司联合提出的Web服务器上的API标准)这一标准,将请求的文件根据文件后缀名的不同,转 ...

  7. java编写简单的语法分析预测程序

    编译原理课程中,编了一个简单的语法分析预测程序,这个程序时根据固定的文法得到预测分析表,然后编写程序来判断表达式是否会正确推到出来. 前提是程序没有左递归符合LL(1)文法: 文法如下: E→TE' ...

  8. Eclipse 入手配置

    工欲善其事,必先利其器 在安装eclipse后进行简单的配置能够为以后的开发提高不少效率,这里慢慢先记录自己的经验. 一.编码配置 utf-8 1.worksplace: 首先设置就是workspac ...

  9. css之子元素获取(未定义高度)父元素的高度

    你可能碰到过这样的需求,一个高度不固定的区域(内容由用户创造),当鼠标经过该区域或者其神马操作时,需要出现一个与该区域一样大的模版: 我们用一个span来处理这个mask.由于 .sample-1 和 ...

  10. 规范的web前端代码

    web前端的代码规范主要针对的是HTML,CSS和javaScript代码. 前端代码规范在不同场合会有差异,但是规范的前端代码应该具有以下特征: 1.符合标准 所谓的标准是指W3C指定的web标准, ...