• 重新整理 .net core 实践篇————polly失败重试[三十四]


    前言

    简单整理一下polly 重试。

    正文

    在开发程序中一般都有一个重试帮助类,那么polly同样有这个功能。

    polly 组件包:

    polly 功能包

    polly.Extensions.Http 专门针对http的扩展包

    Miscrosoft.Extension.Http.Polly 看到这个名字,那么99%是针对官方.net core的扩展包,是HttpClientFactory 的扩展。

    polly有下面一些功能:

    1. 失败重试

    2. 服务熔断

    3. 超时处理

    4. 舱壁处理

    5. 缓存策略

    6. 失败降级

    7. 组合策略

    其他都好理解,但是舱壁处理 是什么呢?

    这个是限流功能,服务定义最大的流量和队列,避免请求量过大而崩溃。

    组合策略,就是对上面的功能可以自由组合。

    polly 使用步骤:

    1. 定于要处理的异常类型和返回值

    2. 定义要处理的工作

    3. 使用定义的策略来执行代码

    polly的源代码:

    https://github.com/App-vNext/Polly

    polly 针对http的扩展包:

    https://github.com/App-vNext/Polly.Extensions.Http

    适合polly 重试的场景:

    1.服务"失败"是短暂的,可自愈的。

    针对这种http请求,无状态的是非常适用的。

    2.服务是"幂等"的,重复调用不会产生副作用

    这个幂等可以简单为多次执行,并不会影响到最初达到的效果。

    比如说个人查询,查询多次的话,效果是相同的。具体幂等可以百度一下,不过觉的看下https://baike.baidu.com/item/%E5%B9%82%E7%AD%89/8600688?fr=aladdin就够了,因为有些人讲的神乎其神。

    具体场景:

    1. 服务闪断

    2. 部分节点不可用

    在使用重试过程中,最好达到下面几个要求:

    1. 设置失败次数

    2. 设置有步长策略的失败等待间隔

    3. 设置降级响应

    4. 设置断路器

    前面说过polly 是针对httpClientFactory 的扩展,那么其融合性其实是非常好的。

    比如说,grpc当监听到AddTransientHttpErrorPolicy错误的时候,那么可以启动对应的策略进行重试,RetryAsync就是polly的扩展,里面设置重试次数20次。

    services.AddGrpcClient<Helloworld.Greeter.GreeterClient>(options =>
    {
    	options.Address = new Uri("https://localhost:5001");
    }).ConfigurePrimaryHttpMessageHandler(provider =>
    {
    	var handle = new SocketsHttpHandler();
    	handle.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true;
    	return handle;
    }).AddTransientHttpErrorPolicy(p=>p.RetryAsync(20));
    

    看下AddTransientHttpErrorPolicy,其实个人感觉RetryAsync倒是没有必要去看,看AddTransientHttpErrorPolicy 是为了知道啥时候会触发这个重试,以及知道如何去定义我们自己的Policy。

    AddTransientHttpErrorPolicy:

    public static IHttpClientBuilder AddTransientHttpErrorPolicy(
    	this IHttpClientBuilder builder, 
    	Func<PolicyBuilder<HttpResponseMessage>, IAsyncPolicy<HttpResponseMessage>> configurePolicy)
    {
    	if (builder == null)
    	{
    		throw new ArgumentNullException(nameof(builder));
    	}
    
    	if (configurePolicy == null)
    	{
    		throw new ArgumentNullException(nameof(configurePolicy));
    	}
    	
    	var policyBuilder = HttpPolicyExtensions.HandleTransientHttpError();
    
    	// Important - cache policy instances so that they are singletons per handler.
    	var policy = configurePolicy(policyBuilder);
    
    	builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(policy));
    	return builder;
    }
    

    从名字中可以看到HandleTransientHttpError就是处理异常的。

    public static PolicyBuilder<HttpResponseMessage> HandleTransientHttpError()
    {
      return Policy<HttpResponseMessage>.Handle<HttpRequestException>().OrTransientHttpStatusCode();
    }
    

    这里表示HttpRequestException 会触发,或者OrTransientHttpStatusCode一些状态码下会触发,看下OrTransientHttpStatusCode。

    OrTransientHttpStatusCode:

    public static PolicyBuilder<HttpResponseMessage> OrTransientHttpStatusCode(
      this PolicyBuilder<HttpResponseMessage> policyBuilder)
    {
      if (policyBuilder == null)
    	throw new ArgumentNullException(nameof (policyBuilder));
      return policyBuilder.OrResult(HttpPolicyExtensions.TransientHttpStatusCodePredicate);
    }
    

    查看HttpPolicyExtensions.TransientHttpStatusCodePredicate:

     private static readonly Func<HttpResponseMessage, bool> TransientHttpStatusCodePredicate = (Func<HttpResponseMessage, bool>) (response => response.StatusCode >= HttpStatusCode.InternalServerError || response.StatusCode == HttpStatusCode.RequestTimeout);
    

    这里面表示 HttpStatusCode.InternalServerError(500)和 HttpStatusCode.RequestTimeout(408) 会进行重试。

    同样可以设置间隔时间进行重试:

    services.AddGrpcClient<Helloworld.Greeter.GreeterClient>(options =>
    {
    	options.Address = new Uri("https://localhost:5001");
    }).ConfigurePrimaryHttpMessageHandler(provider =>
    {
    	var handle = new SocketsHttpHandler();
    	handle.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true;
    	return handle;
    }).AddTransientHttpErrorPolicy(p=>p.WaitAndRetryAsync(20,i=>TimeSpan.FromSeconds(2)));
    

    还可以使用WaitAndRetryForever 表示一直重试,直到成功,看需求。

    同样也可以自定义一些状态或者一些情况,做一些事情:

    var reg = services.AddPolicyRegistry();
    
    reg.Add("retryforever", Policy.HandleResult<HttpResponseMessage>(message =>
    {
    	return message.StatusCode == System.Net.HttpStatusCode.Created;
    }).RetryForever());
    
    services.AddHttpClient("GreeterClient").AddPolicyHandlerFromRegistry("retryforever");
    

    上面表示针对GreeterClient客户端,增加一些retryforever的处理策略。

    后面会介绍这种策略架子是如何实现的,在细节篇。

    那通过Polic就可以针对不同场景,进行定义不同的策略,做出一些相应。看项目需求,这里就不多介绍了,每个项目都不一样。

    下一节polly熔断。

  • 相关阅读:
    Sending post
    <<the not so short introduction to Latex2e >> 读书笔记
    Latex 书签中文乱码解决方案
    VisualSVN迁移到其他服务器 子曰
    C#遍历DataSet中数据的几种方法总结 子曰
    Extjs formpanel加载数据的两种方式 子曰
    向老销售取经,学来的一点软件销售技巧 子曰
    extjs 实现 NumberField 即时计算 子曰
    Ext.form.DateField简单用法及日期范围控制 子曰
    解决.aspx中插入浮动广告不滚动问题 子曰
  • 原文地址:https://www.cnblogs.com/aoximin/p/14961359.html
Copyright © 2020-2023  润新知