专栏首页雪雁的专栏AspNet.Core之使用CancellationToken来提高应用负载

AspNet.Core之使用CancellationToken来提高应用负载

背景

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

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

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

头脑风暴

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

① F5刷新

② 转向其他页面

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

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

在异步编程中能向任务发出Cancellation信号,停止web服务器后端查询行为。在.NET中,这是使用CancellationToken完成的:

  • 取消令牌的实例传递到异步任务
  • 异步任务监视令牌,以查看请求是否已经被取消。
  • 如果请求取消,则应停止执行正在执行的操作。.NET中的大多数异步方法将具有接受取消令牌的重载。

tip

本文取消的请求,指的是耗时长的服务端读取请求(返回数据但不修改数据的查询),取消已修改数据的请求对于用程序可能不是一个好的选择:

① 是否真的要因为用户导航到应用的另一个页面而取消保存?也许可以,但也可能不会。

② 提高了复杂性,因为数据库服务器可能需要回滚事务,这是一项昂贵的操作。

AspNetCore实践

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

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

P1 监测CancellationToken令牌

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

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

上述EF的调用api支持取消异步操作,故很容易取消SQL的查询行为;对于自定义的长耗时查询行为,可以使用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);
}

P2 处理取消异步操作向上抛出的异常处

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);
        }
    }
}

P3 想要得到CTO的大拇指,继续思考吧

以上是后端程序员利用取消机制缓解异步查询瓶颈的操作,从web应用全流程角度思考,这个优化还能提升吗? ?

> 以上是传统的网页请求场景,在取消请求时,浏览器帮助我们发起了Cancellation信号。

> 想想日益常见的SPA程序(单页面程序),绝大部分页面请求都是Ajax请求,你点击应用的另外一个“页面”(JS代码维护页面导航),浏览器不会自动取消请求。所以在SPA应用中要前端自己发出取消请求的信号:

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

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

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

本文分享自微信公众号 - magiccodes(xl----0)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于Http协议,你必须要知道的

    HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网服务器传输超文本到本地浏览器的传送协议。HTTP ...

    心莱科技雪雁
  • 我是一个杀毒软件线程

    夜深了,我的工作忙完了,准备去sleep一会儿。路过安全分析实验室的门口,看到实验室大牛老周还在埋头研究。

    心莱科技雪雁
  • Docker最全教程——从理论到实战(八)

    在本系列教程中,笔者希望将必要的知识点围绕理论、流程(工作流程)、方法、实践来进行讲解,而不是单纯的为讲解知识点而进行讲解。也就是说,笔者希望能够让大家将理论、...

    心莱科技雪雁
  • web统计原理及实现方法汇总总结—网站统计中的数据收集

    在php、jsp、asp后端总揽一切的时代,网站统计基本是后台的事情——其实web开发,也没有前端这个职位,网站设计(现在的UI)不仅要前途还要用dreamwa...

    周陆军
  • ajax传参形式

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    suveng
  • 熊市结束的信号?

    BTC的历史最高点出现在2017年12月,接近20000$,最近的一个最低点是2018年12月,大概为3200$,跌掉了80%多。

    申龙斌
  • SpringApplication到底run了什么(下)

    在上篇文章中SpringApplication到底run了什么(上)中,我们分析了下面这个run方法的前半部分,本篇文章继续开工

    Java学习录
  • 学习Javascript之模拟实现call,apply

    总括: 本文从零开始通过提出问题然后解决问题的方式模拟实现了比较完善的call和apply方法

    Damonare
  • consul agent的一个故障

    如果consul agent用docker容器来管理,启动和停止是批量的话,会导致consul-marathon应用服务注册丢失的问题,错误日志如下:

    domain0
  • 原 荐 neo-共识算法dBFT 源码解析

    魂祭心

扫码关注云+社区

领取腾讯云代金券