.net core 发起web请求_结合ASP.NET Core聊一聊取消机制缓解web后台性能压力

35d8f9e4698aa8d79560c89b0e4137d0.png

背景

已经有很多文章记录了 web程序中采用异步编程的优势和.Net异步编程的用法, 异步编程虽然不能解决查询数据库的瓶颈, 但是利用线程切换,能最大限度的弹性利用工作线程, 提高了web服务的响应能力。

9012年了,再不会异步编程你是真老了

本文要说的是利用取消机制缓解后台的查询瓶颈,开发者只需在 MVC/WebAPI查询方法体内关注CancellationToken并适时取消异步任务, 这将大大提高应用的响应能力。

头脑风暴

想象你请求某网站页面,该页面正闪着菊花试图努力绽放(正在加载),最终你忍不了:

① F5刷新

② 转向其他页面

③ 点击浏览器“停止”按钮

对于可怜的服务器,用户快速刷新5次,服务器将被迫接受 5倍的工作量,这是因为即使用户刷新了浏览器(或点击停止按钮), 虽然取消了原始浏览器请求,但是Web服务器并不Care,仍然按部就班处理进入HTTP pipeline的请求(MVC/WebAPI 中默认行为),其他②③场景类似。

在异步编程中能向任务发出Cancellation信号,停止web服务器一切后端查询行为。
(此处更正,不应强调异步编程,能否发送取消信号是客户端决定,服务端要做的是准备好信号接收器CancellationToken, 也就是说本文的取消机制对异步、 同步均有效)

在.NET中,这是使用CancellationToken完成的。

  • 取消令牌的实例传递到异步任务
  • 异步任务监视令牌,以查看请求是否已经被取消。
  • 如果请求取消,则应停止执行正在执行的操作。.NET中的大多数异步方法将具有接受取消令牌的重载。
本文所说的请求是,耗时长的服务端读取查询(返回数据但不修改数据的查询)。取消已修改数据的请求对于用程序可能不是一个好的选择:
  • 是否真的要因用户导航到应用程序中的另一个页面而取消保存?也许可以,但也可能不会。
  • 除了数据问题,这也不会提高性能,因为数据库服务器将需要回滚该事务,这可能是一项昂贵的操作。

http://ASP.NET Core实践

监测CancellationToken令牌

访问 MyReallySlowReport页面,等待5s,最终他们放弃了,去了其他页面:

53c344e81603ce68be041d31b105785b.png

所有正在进行的请求都将被取消。

MVC/WebAPI能接受到取消请求的信号。开发者只需要在Controller Action中添加CancellationToken参数,并在后续行为中监测该取消信号

浏览器取消请求时, http:// ASP.NET Core根据 CancellationTokenModelBinder自动将 HttpContext.RequestAbortedtoken绑定到Action的 CancellationToken参数,CancellationTokenModelBinder将会在调用AddMvc()或services.AddMvcCore()时被注入。
public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
    List<ReportItem> items;
    using (ApplicationDbContext context = new ApplicationDbContext())
    {
        items = await context.ReportItems.ToListAsync(cancellationToken);
    }
    return View(items);
}

很容易取消SQL的查询行为,因为上述EF的调用api支持取消异步操作; 对于自定义的长耗时查询行为,可以使用CancellationToken的原生触发用法:

public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
    List<ReportItem> items;
    using (ApplicationDbContext context = new ApplicationDbContext())
    {
        items = await context.ReportItems.ToListAsync(cancellationToken);
    }

    foreach (var item in items)
    {
        cancellationToken.ThrowIfCancellationRequested();
            // slow non-cancellable work
            Thread.Sleep(1000);
    }
    return View(items);
}

从以上代码也可推断出: CancellationToken 适用于同步方法。

处理取消操作抛出的异常

Web服务器触发取消信号,一般会向上会抛出 OperationCanceledException 或者 TaskCancellationException,所以为了记录这种非常规异常,建议采用独立的ExceptionFilter记录。

public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
{
    private readonly ILogger _logger;

    public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<OperationCancelledExceptionFilter>();
    }
    public override void OnException(ExceptionContext context)
    {
        if(context.Exception is OperationCanceledException)
        {
            _logger.LogInformation("Request was cancelled");
            context.ExceptionHandled = true;
            context.Result = new StatusCodeResult(400);
        }
    }
}

SPA应用

以上是后端程序员利用取消机制 缓解后台性能压力,针对的是浏览器触发的取消操作。
从web请求的产生来源分析,除了浏览器能发起请求,编程也可以发起请求

想想日益常见的SPA程序(单页面程序),绝大部分页面请求都是ajax请求,你点击应用的另外一个“页面(JS代码维护页面导航),浏览器不会自动取消请求。

在SPA应用中,前端发起的ajax请求,若要取消,是需要以编程方式取消的。 所以我墙裂建议, 在2C的SPA应用中,切换“页面“”时请 终止原页面的所有ajax请求。

var xhr = $.get("/api/myslowreport", function(data){
  //show the data
});

//If the user navigates away from this page
xhr.abort() 

5e47b6fd17f03705a8b0a9f4c4e1a954.png

总结输出

  1. 利用取消机制的前置条件 在于 请求能够发出取消指令
  2. 利用取消机制的关键在于监测取消令牌,并作出取消操作
  3. 请求不但可以从浏览器发起,ajax也可以发起, 在SPA程序中极其常见,故取消机制需要关注SPA应用的ajax取消

That‘s all ,前后端程序猿通力配合,应用的吞吐量和响应能力极大提升, CTO要给各位加薪了。

  • https://www.cnblogs.com/JulianHuang/p/10678887.html
  • https://www.cnblogs.com/JulianHuang/p/10572840.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值