ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【西天取经】实现net core自定义服务端熔断

2020-09-27 09:32:47  阅读:206  来源: 互联网

标签:core 自定义 Random public context ._ using net logger


网上关于net core实现服务熔断的都是客户端的例子,下面我来分享一个服务器端的例子,可以针对每一个用户请求做到服务器端熔断的操作。

通过middleware可以实现针对用户级别的流控。感谢张浩帮忙。

CircuitBreakerMiddleware.cs

 1 using System;
 2 using System.Collections.Concurrent;
 3 using System.Net;
 4 using System.Threading.Tasks;
 5 using Microsoft.AspNetCore.Http;
 6 using Microsoft.AspNetCore.Http.Extensions;
 7 using Microsoft.Extensions.Configuration;
 8 using Microsoft.Extensions.Logging;
 9 using Polly;
10 using Polly.CircuitBreaker;
11 
12 namespace CircuitBreakerDemo
13 {
14     /// <summary>
15     /// net core 实现自定义断路器中间件
16     /// </summary>
17     public class CircuitBreakerMiddleware : IDisposable
18     {
19         private readonly RequestDelegate _next;
20         private readonly ConcurrentDictionary<string, AsyncPolicy> _asyncPolicyDict = null;
21         private readonly ILogger<CircuitBreakerMiddleware> _logger;
22         private readonly IConfiguration _configuration;
23 
24         public CircuitBreakerMiddleware(RequestDelegate next, ILogger<CircuitBreakerMiddleware> logger, IConfiguration configuration)
25         {
26             this._next = next;
27             this._logger = logger;
28             this._configuration = configuration; //未来url的断路规则可以从config文件里读取,增加灵活性
29             logger.LogInformation($"{nameof(CircuitBreakerMiddleware)}.Ctor()");
30             this._asyncPolicyDict = new ConcurrentDictionary<string, AsyncPolicy>(Environment.ProcessorCount, 31);
31         }
32 
33         public async Task InvokeAsync(HttpContext context)
34         {
35             var request = context.Request;
36             try
37             {
38                 await this._asyncPolicyDict.GetOrAdd(string.Concat(request.Method, request.GetEncodedPathAndQuery())
39                                                      , key => Policy.Handle<Exception>()
40                                                                     .AdvancedCircuitBreakerAsync
41                                                                     (
42                                                                         //备注:20秒内,请求次数达到10次以上,失败率达到20%后开启断路器,断路器一旦被打开至少要保持5秒钟的打开状态。
43                                                                         failureThreshold: 0.2D,                       //失败率达到20%熔断开启
44                                                                         minimumThroughput: 10,                        //最多调用10次
45                                                                         samplingDuration: TimeSpan.FromSeconds(20),   //评估故障持续时长20秒
46                                                                         durationOfBreak: TimeSpan.FromSeconds(5),     //恢复正常使用前电路保持打开状态的最少时长5秒
47                                                                         onBreak: (exception, breakDelay, context) =>  //断路器打开时触发事件,程序不能使用
48                                                                         {
49                                                                             var ex = exception.InnerException ?? exception;
50                                                                             this._logger.LogError($"{key} => 进入打开状态,中断持续时长:{breakDelay},错误类型:{ex.GetType().Name},信息:{ex.Message}");
51                                                                         },
52                                                                         onReset: context =>                           //断路器关闭状态触发事件,断路器关闭
53                                                                         {
54                                                                             this._logger.LogInformation($"{key} => 进入关闭状态,程序恢复正常使用");
55                                                                         },
56                                                                         onHalfOpen: () =>                             //断路器进入半打开状态触发事件,断路器准备再次尝试操作执行
57                                                                         {
58                                                                             this._logger.LogInformation($"{key} => 进入半开状态,重新尝试接收请求");
59                                                                         }
60                                                                     )
61                                                      )
62                                             .ExecuteAsync(async () => await this._next(context))
63                                             ;
64             }
65             catch (BrokenCircuitException exception)
66             {
67                 this._logger.LogError($"{nameof(BrokenCircuitException)}.InnerException.Message:{exception.InnerException.Message}");
68                 var response = context.Response;
69                 response.StatusCode = (int)HttpStatusCode.BadRequest;
70                 response.ContentType = "text/plain; charset=utf-8";
71                 await response.WriteAsync("Circuit Broken o(╥﹏╥)o");
72             }
73 
74             //var endpoint = context.GetEndpoint();
75             //if (endpoint != null)
76             //{
77             //    var controllerActionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
78             //    var controllerName = controllerActionDescriptor.ControllerName;
79             //    var actionName = controllerActionDescriptor.ActionName;
80             //    if (string.Equals(controllerName, "WeatherForecast", StringComparison.OrdinalIgnoreCase)
81             //        && string.Equals(actionName, "Test", StringComparison.OrdinalIgnoreCase))
82             //    {//针对某一个控制器的某一个action,单独设置断路
83             //        await Policy.Handle<Exception>().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10)).ExecuteAsync(async () => await this._next(context));
84             //    }
85             //    else
86             //    {
87             //        await this._next(context);
88             //    }
89             //}
90         }
91 
92         public void Dispose()
93         {
94             this._asyncPolicyDict.Clear();
95             this._logger.LogInformation($"{nameof(CircuitBreakerMiddleware)}.Dispose()");
96         }
97     }
98 }
CircuitBreakerMiddleware.cs

Startup.cs

 1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 2 {
 3     if (env.IsDevelopment())
 4     {
 5          app.UseDeveloperExceptionPage();
 6     }
 7 
 8     app.UseRouting();
 9 
10     //注意位置在Routing下面,UseEndpoints上面
11     app.UseMiddleware<CircuitBreakerMiddleware>();
12 
13     app.UseEndpoints(endpoints =>
14     {
15          endpoints.MapControllers();
16     });
17 }
Startup.cs

WeatherForecastController.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using Microsoft.AspNetCore.Mvc;
 5 using Microsoft.Extensions.Logging;
 6 
 7 namespace CircuitBreakerDemo.Controllers
 8 {
 9     [ApiController]
10     [Route("[controller]")]
11     public class WeatherForecastController : ControllerBase
12     {
13         private static readonly string[] Summaries = new[]
14         {
15             "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
16         };
17 
18         private static Random _Random = new Random();
19 
20         private readonly ILogger<WeatherForecastController> _logger;
21 
22         public WeatherForecastController(ILogger<WeatherForecastController> logger)
23         {
24             this._logger = logger;
25         }
26 
27         [HttpGet]
28         public IEnumerable<WeatherForecast> Get()
29         {
30             if (_Random.Next(Summaries.Length) % 3 == 0)
31             {
32                 throw new Exception("程序运行错误");
33             }
34 
35             return Enumerable.Range(1, 5).Select(index => new WeatherForecast
36             {
37                 Date = DateTime.Now.AddDays(index),
38                 TemperatureC = _Random.Next(-20, 55),
39                 Summary = Summaries[_Random.Next(Summaries.Length)]
40             })
41             .ToArray();
42         }
43 
44         [HttpGet("test")]
45         public string Test()
46         {
47             if (_Random.Next(Summaries.Length) % 3 == 0)
48             {
49                 throw new Exception("程序运行错误");
50             }
51             return Summaries[_Random.Next(Summaries.Length)];
52         }
53     }
54 }
WeatherForecastController.cs

项目跑起来就是各种刷新,然后就可以看到结果了。

标签:core,自定义,Random,public,context,._,using,net,logger
来源: https://www.cnblogs.com/xitianqujing/p/13737729.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有