熔断和降级的初步详解实现(NET Core控制台输出讲解Polly)


概述

很多朋友包括我,对于“八股文”可以说是比较熟练的,每次面试前都会专研不少东西,各种固定答案、专业术语都是张口就来,一个字,稳。

八股文:程序员八股文是指程序员在面试过程中经常被问到的问题,大多都有固定化、格式化的答案,俗称为面经。

八股文是明清科举考试的一种文体,也称制义、制艺、时文、八比文。

八股文就是指文章的八个部分,文体有固定格式:由破题、承题、起讲、入题、起股、中股、后股、束股八部分组成,题目一律出自四书五经中的原文。

后四个部分每部分有两股排比对偶的文字,合起来共八股。

相信大家对熔断、降级、隔离、限流、容灾备份、故障转移、异地多活等专业术语不陌生吧,或多或少都能聊上一两句。

但是在实际开发中却望着键盘发呆,不知道怎么实现,今天我们就简单演示一下再项目当中怎么实现熔断、降级。

实现的方式有很多,我们这里讲解Polly,但是大家不要过分依赖,可以多种方式进行预演防范。

强如淘宝,在今年(2021年10月20号)20点10分左右都崩了,20点27分左右修复。

熔断和降级概念理解

熔断机制概念

当下游服务因访问压力过大而响应变慢或失败,或者下游服务出现异常时,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

PS:如果项目中不使用熔断将会影响到整个系统的使用。

 

举例:

家庭里有很多大功率电器(微波炉,电磁炉,电炒锅,空调,饮水机,电热水器、浴霸、太阳能抽水电机等),

一旦我们全部开启大功能电器,就会造成超负荷运行引起跳闸停电,导致家里面全面停电,这就不符合用电目的,我们想哪个大功能超负荷就停哪个,不能因为局部影响全局。

这个时候我们需要在家庭总电闸下面加装二级电闸、三级电闸.....,达到一机一闸一保护的目的(也可以多个电器安装一个电闸)。

如果在这个例子中,把用电换成我们程序中的接口(接口能承受3000人同时访问),然后把大功率电器替换成我们的接口调用者。

当接口的并发超过3000这个点的时候接口将会挂掉,导致服务器崩溃,作为调用者并不能控制这个点。

为了防止我们的接口发生崩溃的情况,我们做一个报警的设置,当发生这个情况的时候暂时切断服务,防止服务崩溃(用户量到达3000的时候,拒绝其他请求,只服务这3000以内的请求)。

降级机制概念

降级是当某个服务出现故障启动熔断机制后,向调用方返回一个替代响应或者规范化的错误响应。

举例:

我们的程序需要发送邮件,首先调用自建邮箱发送,当自建邮箱发送失败后调用网易邮箱发送邮件,如果网易邮箱发送失败,那么我们就调用 QQ 邮箱发送,如果 QQ 邮箱也发送失败,那么我们就返回发送失败响应。
降级也可以看作服务的选择性放弃。
例如1:上面的多个大功能电器不需要同时运行时,我们可以关闭其他电器,等待当前电器用完后在使用。
例如2:李佳琪和薇娅的直播带货时,平台流量优先倾斜,导致其他主播的直播间卡慢不清晰等问题,等待李佳琪薇娅直播结束后其他主播恢复正常。
例如3:李佳琪和薇娅的直播带货时,平台流量优先倾斜,导致其他主播的直播间卡慢不清晰等问题,等待李佳琪薇娅直播结束后其他主播恢复正常。

当服务接口发生错误的时候,可以找到一个替代方法进行使用。这个方法可能是启用另一台服务器的接口,也可能是只返回“服务器繁忙请重试的提示”。总之不会把一个系统级别的问题暴露给用户。

什么是 Polly

暂时我所了解的处理熔断降级的框架有NetFlix的Hystrix框架和Polly框架。我们这里使用Polly。

Polly 是被 .NET 基金会认可的弹性和瞬态故障处理库,允许开发人员以流畅和线程安全的方式表达策略,如重试、断路器、超时、舱壁隔离和回退。

Polly 的7种策略 [1]:重试、断路(熔断)、降级、超时、隔离、缓存以及策略包集合 Polly 的核心是动作和故障,其中动作主要包含降级、熔断和重试等,策略则包含用来执行的代码。

1、重试(Retry):

  当程序发生短暂的故障、并且故障在延迟后,可以自动纠正的,前期是暂时的我们可以配置自动重试。

2、断路器(Circuit-Breaker):

  当一个系统陷入严重的问题时,让系统快速的失败,比让用户一直等待着要好的多,保护一个系统不受过载的影响,可以帮助它快速的恢复。

3、超时(Timeout):

  在等待一定的时间后,没有返回相应的结果,保证程序不会一直等待下去,使调用者不必一直的等待下去。

4、隔离(Bulkhead Isolation):

  当进程出现故障的时,一台主机中的多个失败的进程,对资源(例如线程/CPU)的一直占用,当下游的系统发生故障的时候,也可能导致上游对资源的调用失败、这两种风险的出现都将导致更大范围的影响、隔离策略是为了防止“一个点的失败导致整盘的失败”把受到管理的操作固定在某个资源中,避免影响到其他的资源。

5、缓存(Cache):

  针对相同的请求,在第一次访问的时候将响应的数据进行缓存,再次访问的时候直接在缓存中提供响应的数据。

6、回退(FallBack):

  当程序发生失败的情况的时候,我们将做些什么,定义一个在程序发生失败的时候要执行的动作。

7、策略组合(PolicyWrap):

  Polly针对不同的故障有不同的策略,我们可以灵活的组合策略,上述的六种策略可以灵活组合使用。

Polly的基本用法

我们创建一个.NET Core 2.1 控制台应用程序,命名为 PollyDemo。

在Nuget中引用第三方库Polly,选择最新稳定版。

1、重试策略(Retry)

我们定义一个 GetUser 方法,这个方法用来模拟网络请求并在方法结尾制造了一个 Http 异常。

在 Main 方法中我们设定了重试次数 5 次,并且规定了重试过程中要执行的业务逻辑,最后调用 Execute 方法指定针对哪段代码执行这个策略。

我们运行代码可以发现当触发异常后,程序不断的重试调用指定的代码段,直到达到重试次数后不再重试并抛出异常。

我们在使用重试策略需要注意的是,当达到重试次数后代码会抛出异常,因此我们必须在将充实策略代码包裹在 try_catch 代码段中。

using Polly;
using System;
using System.Net.Http;
using System.Threading;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //如果程序发生错误将重新执行 5 次
                Policy.Handle<HttpRequestException>().Retry(5, ((exception, count, context) =>
                {
                    Console.WriteLine($"执行失败,第 {count} 次重试");
                })).Execute(GetUser);
            }
            catch (Exception e)
            {
                Console.WriteLine("异常抛出:"+e.Message);
            }
            Console.Read();
        }

        //开始执行代码块
        static void GetUser()
        {
            Console.WriteLine("开始执行");
            Thread.Sleep(1000);
            throw new HttpRequestException();  //直接定义错误抛出
        }
    }
}

 

执行结果

 

2、断路器(Circuit-Breaker)

 

程序首次被访问如果连续出现三次错误后,将暂停3秒,三秒结束后 可以被继续访问,

继续访问时 如果第一次就出现错误 ,继续熔断10次。

using Polly;
using System;
using System.Net.Http;
using System.Threading;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //连续访问3ci
            var PolicyExecutes =
                Policy<object>.Handle<Exception>()
                .CircuitBreaker(3, TimeSpan.FromSeconds(3));

            //模拟访问10次
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    PolicyExecutes.Execute(() =>
                    {
                        Console.WriteLine("********************开始执行程序**************************");
                        throw new Exception("异常");
                    });
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception信息{i}" + ex.Message);
                }
                //一秒运行一次
                Thread.Sleep(1000);
            }
            Console.Read();

        }
    }
}

执行结果

 

3、超时策略(Timeout)

程序本身没有错误就是执行的时间超过了我们制定的超时策略的时间然后程序就抓捕到超时的异常。

using Polly;
using Polly.Timeout;
using System;
using System.Net.Http;
using System.Threading;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //超时策略(程序没错,只是执行时间超过设置的时间)
                Policy policy = Policy.Timeout(3, TimeoutStrategy.Pessimistic);

                policy.Execute(() =>
                {
                    Console.WriteLine("********************开始执行程序**************************");
                    Console.WriteLine("等待执行中...");
                    Thread.Sleep(5000); //设置5s超时
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine("执行超时,请重试");
            }
            Console.Read();

        }
    }
}

执行过程

 

4、隔离策略(Bulkhead Isolation)

制定策略最大的并发数为5

using Polly;
using Polly.Timeout;
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Policy PolicyExecutes = Policy.Bulkhead(5);
            //程序运行6次 总会有一个失败的,但是这个失败的不会影响其他5个的执行结果
            for (int i = 0; i < 6; i++)
            {
                Task.Factory.StartNew(() =>
                {
                    try
                    {
                        PolicyExecutes.Execute(() =>
                        {
                            Console.WriteLine($"********************开始执行程序**************************");
                            Thread.Sleep(5000); //为了看出效果,设置5s停顿,便于并发执行错误
                        });
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                });
            }
            Console.Read();

        }
    }
}

执行结果

 

5、缓存策略(Cache)

在开发时我们会把频繁使用并且很少变化的资源缓存起来,来提高系统的性能。

Polly 提供了强大且易于上手的缓存策略的支持,使得我们不用再手动编写缓存策略。

这里我不提供示例代码,一来我暂时还没使用这个策略,二来这一小部分需要根据不同项目和不同公司的框架来订。

using System;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //Policy.Cache 可以指定 过期时间,绝对过期时间,滑动过期时间等
            //Policy 的缓存策略的制定
            MemoryCache memoryCache = null;
            var PolicyExecutes = Policy.Cache(memoryCache, TimeSpan.FromMinutes(5));
            Console.Read();
        }
    }
}

6、回退(FallBack)

当主程序发生错误是我们启动备用的程序进行程序处理。

using Polly;
using System;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var PolicyExecute = Policy.Handle<Exception>().Fallback(() =>
            {
                Console.WriteLine($"你的程序报错了,我是替代程序!");

            });

            //执行
            PolicyExecute.Execute(() =>
            {
                Console.WriteLine("开始执行程序");
                Console.WriteLine("");
                throw new Exception();
            });
            Console.Read();
        }
    }
}

执行结果

 

7、策略组合(PolicyWrap)

 PolicyWrap的上面六种策略可以任意的组合起来使用:我们将超时策略(Timeout)加上回退(FallBack)策略组合使用。

using Polly;
using Polly.Timeout;
using System;
using System.Threading;

namespace PollyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Policy PolicyExecute = Policy.Handle<Exception>().Fallback(() =>
            {
                Console.WriteLine("你的执行程序超时了,我是替代程序!");

            });
            //超时策略
            PolicyExecute = PolicyExecute.Wrap(Policy.Timeout(3, TimeoutStrategy.Pessimistic));
            //执行
            PolicyExecute.Execute(() =>
            {
                Console.WriteLine($"我是一开始的执行程序");
                Console.WriteLine("");
                Thread.Sleep(5000);
            });
            Console.Read();
        }
    }
}

执行结果

 

总结

本文开头主要介绍了熔断和降级的相关概念,然后用讲解了 Polly 的其中策略,这些都可以作为掌握 Polly 的基础。

因为 Polly 是一个强大而丰富的 .NET 第三方库,无法通过一篇文章具体而又详细的讲解出来,因此对于 Polly 和 熔断以及降级有兴趣的同学可以上 Polly 官方文档中具体学习。

参考文献

1.Polly的7种策略:https://blog.csdn.net/sd7o95o/article/details/117003880

2.使用.NetCore 控制台演示 熔断 降级(polly)

 

 
欢迎关注订阅微信公众号【熊泽有话说】,更多好玩易学知识等你来取
作者:熊泽-学习中的苦与乐
公众号:熊泽有话说
出处: https://www.cnblogs.com/xiongze520/p/15693245.html
您可以随意转载、摘录,但请在文章内注明作者和原文链接。  

 

 

 

文章来源:https://www.cnblogs.com/xiongze520/p/15693245.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:windows平台的分布式微服务解决方案(5)--Web服务/WebApi的负载均衡
下一篇:解决:旧项目升级新版Unity2021导致Visual Studio无法使用
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

熔断降级初步详解实现NET Core控制台输出讲解Polly
.NET Core定时任务(控制台程序)
如何提升.NET控制台应用体验?
.NET Core,.NET5 固定输出目录,不要版本目录
详解ElasticAPM实现微服务链路追踪(NET
Webpack讲解:devTool中SourceMap模式详解
.NET Core 复制nuget包依赖dll到输出目录
使用.NET 6开发TodoList应用(31)——实现基于Github ActionsACICI/CD
使用 .NET Core Quartz.NET 实现任务调度持久化:更相信配置任务调度
使用Hot Chocolate.NET 6构建GraphQL应用(4) —— 实现Query映射功能
Linq to SQL语句基础讲解
.NET Core 实现动态代理做AOP(面向切面编程)
.NET Core MVC 实现长时间任务进度显示
WPF 双向绑定到非公开 set 方法属性在 NET 45 NET Core 行为不同
.net Core项目 IIS部署运行异常信息输出
使用.NET 6开发TodoList应用(26)——实现ConfigurationOption强类型绑定
使用Hot Chocolate.NET 6构建GraphQL应用(3) —— 实现Query基础功能
.NET Core 利用委托实现动态流程组装
使用.NET 6开发TodoList应用(11)——使用FluentValidationMediatR实现接口请求验证
使用.NET 6开发TodoList应用(30)——实现Docker打包部署

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划 容差配置 SAP事务码 SAP基础 TCODE Basis 事务代码 MMNR 编号区间 采购实操 组织架构 OMSF SAP实操 FI配置
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码