.NET6之Mini API【二十四、用Polly重试】

内容纲要

为了保障系统的稳定和安全,在调用三方服务时,可以增加重试和熔断。重试是调用一次失败后再试几试,避免下游服务一次闪断,就把整个链路终止;熔断是为了防止太多的次数的无效访问,导致系统不可知异常。

Polly是独立的重试机制的三方库,这里只说明在使用httpclient时,请求下游api时的重试和熔断。需要引入NuGet包

Microsoft.Extensions.Http.Polly。

先看一个简单的重试

  1. using Polly;
  2. var builder = WebApplication.CreateBuilder(args);
  3. builder.Services
  4. .AddHttpClient("RetryClient", httpclient =>
  5. {
  6. httpclient.BaseAddress = new Uri("http://localhost:5258");
  7. })
  8. .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryAsync(3));
  9. var app = builder.Build();
  10. //调用httpclient
  11. app.MapGet("/test", async (IHttpClientFactory httpClientFactory) =>
  12. {
  13. try
  14. {
  15. var httpClient = httpClientFactory.CreateClient("RetryClient");
  16. var content = await httpClient.GetStringAsync("other-api");
  17. Console.WriteLine(content);
  18. return "ok";
  19. }
  20. catch (Exception exc)
  21. {
  22. if (!Count.Time.HasValue)
  23. {
  24. Count.Time = DateTime.Now;
  25. }
  26. return $"{exc.Message} 【次数:{Count.I++}】 【{Count.Time.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}】";
  27. }
  28. });
  29. //被调用的接口,返回状态码500
  30. app.MapGet("/other-api", (ILogger<Program> logger) =>
  31. {
  32. logger.LogInformation($"失败:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
  33. return Results.StatusCode(500);
  34. });
  35. app.Run();
  36. static class Count
  37. {
  38. public static int I = 1;
  39. public static DateTime? Time;
  40. }

返回的结果:

通过AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryAsync(3));我们让请求进行了3次重试,加上原本的一次,就是4次请求。在红色框时,会发现请求集中在极短的时间内,如果下游服务有故障,可能不会在这么短的时间内自动恢复,更好的做法是:根据重试的次数,来延长(或随机,或自建延时算法)请求的时间,比如:

  1. .AddTransientHttpErrorPolicy(policyBuilder =>
  2. policyBuilder.WaitAndRetryAsync(3, retryNumber =>
  3. {
  4. switch (retryNumber)
  5. {
  6. case 1:
  7. return TimeSpan.FromMilliseconds(500);
  8. case 2:
  9. return TimeSpan.FromMilliseconds(1000);
  10. case 3:
  11. return TimeSpan.FromMilliseconds(1500);
  12. default:
  13. return TimeSpan.FromMilliseconds(100);
  14. }
  15. }));

这时的结果如下,基本按照我们设置的时间来重试的:

还有几种重试策略,如下:

  1. //一直重试
  2. .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryForeverAsync());
  3. //每2秒重试一次
  4. .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.WaitAndRetryForeverAsync(retryNumber =>
  5. {
  6. Console.WriteLine(retryNumber);
  7. return TimeSpan.FromSeconds(2);
  8. }));
  9. //在5秒内4次请求,如果50%失败,就熔断10秒
  10. .AddTransientHttpErrorPolicy(policyBuilder =>
  11. policyBuilder.AdvancedCircuitBreakerAsync(0.5d, TimeSpan.FromSeconds(5), 4, TimeSpan.FromSeconds(10)));

熔断是保护服务的手段,在本例中具体用法如下:

  1. builder.Services
  2. .AddHttpClient("RetryClient", httpclient =>
  3. {
  4. httpclient.BaseAddress = new Uri("http://localhost:5258");
  5. })
  6. .AddTransientHttpErrorPolicy(policyBuilder =>
  7. policyBuilder.WaitAndRetryAsync(3, retryNumber =>
  8. {
  9. switch (retryNumber)
  10. {
  11. case 1:
  12. return TimeSpan.FromMilliseconds(500);
  13. case 2:
  14. return TimeSpan.FromMilliseconds(1000);
  15. case 3:
  16. return TimeSpan.FromMilliseconds(1500);
  17. default:
  18. return TimeSpan.FromMilliseconds(100);
  19. }
  20. }))
  21. //熔断
  22. .AddTransientHttpErrorPolicy(policyBuilder =>
  23. policyBuilder.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)));

CircuitBreaker控制如果有6次失败的请求,就暂停30秒,具体提示如下:

全部.NET6之MiniAPI-PDF版本下载地址 https://club.51aspx.com/circle/10569.html

.NET

.NET6之Mini API【二十三、Refit】

2022-7-12 20:43:57

.NET

.NET6之Mini API【二十五、Dapper】

2022-7-12 20:58:50

0 条回复 A文章作者 M管理员
欢迎您,新朋友,感谢参与互动!
    暂无讨论,说说你的看法吧
个人中心
今日签到
私信列表
搜索