【给中高级开发者】构建高性能ASP.NET应用的几点建议

如果你在构建一个面向公众的web站点,那么在项目结尾时你想要实现的就是web负载性能良好。这意味着,你要确保你的产品在高负载下(50个并发用户或者每秒200个用户等等)能够运行,即使你认为此时不会有那么大的负载。久而久之,你的web站点可能吸引越来越多的用户,此时如果web的负载难以让人忍受时,那么自然而然网站开始走下坡路,意味着客户流失以及名誉受损。

那么可以采取哪些措施可以使得一个ASP.NET或者ASP.NET MVC应用更加高性能呢?

早期阶段就要对应用进行负载测试

大多数开发者趋向在应用开发完成后,集成测试和回归测试通过后才进行负载测试。尽管在开发完成后执行一次负载测试好过不做,但是一旦完成了代码的编写,修复性能问题就为时已晚了。这个问题最常见的例子就是当应用程序在负载测试时不能正确响应时,就会考虑向外扩展(增加更多的服务器)。有时这是不可能的,因为代码不适合实现扩展服务器。比如当对象是存储在Session中并不可序列化时,这样添加更多的web节点或者工作者进程就是不可能的。如果你在开发的早期阶段就发现你的应用可能要部署到多台服务器上,那么你应该在配置和服务器的数量等方面都要让测试环境和最终环境尽可能地接近,这样你的代码会更容易适应。

使用高性能类库

近来我在诊断web站点的性能问题时发现了代码中的一个热点问题:来自第三方web服务的JSON信息必须要被反序列化多次。那些Json信息是由Newtonsoft.Json反序列化的,并且证明了Newtonsoft.Json在反序列化时不是最快的类库,然后我们使用了一个更快的类库(如ServiceStack)替代了Json.Net,并获得了更好的结果。

如果我们在挑选了Json.Net作为序列化类库的早期阶段就完成了负载测试,那么我们就会更早地发现性能问题,我们就不必再代码中做这么多的修改了,也不必再次完整地重新测试了。

你的应用是CPU密集还是IO密集的?

在开始实现web应用以及设计项目时,你要首先考虑的一件事就是你的应用是CPU密集的还是IO密集的?这对于了解扩展应用的策略是很重要的。

比如,如果你的应用是CPU密集的,那么你可能想使用同步模式,并行处理等等。然而,对于一个有很多IO受限的操作(例如和外部web服务或者网络资源如数据库通讯)的产品,基于Task的异步模式可能对于向外扩展更有帮助。此外,为了在未来的某天能够创建Web Gardens和Web Farms,你可能想有一个集中式的缓存系统,这样就实现了跨越多个工作者进程或服务的负载。

使用基于Task的异步模型,但要慎重

如果你的产品依赖许多IO受限的操作,或者包括了可能需要消耗宝贵的IIS线程等待一个操作完成的长时间运行的操作,你最好为ASP.NET MVC项目考虑使用基于Task的异步模式。

互联网上有很多关于异步的ASP.NET MVC actions的手册(比如这个),所以这篇博客尽量避免介绍关于异步的知识点。然而,必须指出ASP.NET
(MVC)中传统的同步action会造成IIS线程繁忙直到操作完成或请求处理完成。这意味着如果如果web应用在等待一个外部的资源(如一个web服务)响应,那么该线程将是繁忙的。.Net线程池中可以用于处理请求的线程数量也是有限的,因此,尽可能快地释放线程是很重要的。基于Task的异步action或方法会在请求处理后释放该线程,然后从线程池中获取新的线程,并使用该新的线程返回该action的结果。这样,多个请求可以由多个线程处理,这会为你的应用带来更好的响应。

虽然TAP模式对于适当的应用来说很方便,但必须要慎重使用。当你使用TAP设计或者实现一个项目时,必须要注意几个点(你可以点击这里查看),然而,开发者使用async和await关键字面临的最大挑战是知道在这个上下文中他们必须略有不同地处理线程。比如,可以创建一个返回Task(如Task《Product》,博客园的markdown不支持单尖括号)的方法,通常你可以对那个Task调用Run()方法或者只调用task.Result来迫使运行该task,直到拿到结果。

分发缓存和会话(session)状态

开发者在单个开发机器上构建一个web应用是非常常见的,并且也会假设该产品运行在单个服务器上,然而对于面向大众的web通常不是这样的。它们往往被部署到一个叫做负载均衡之后的多个服务器上。尽管你仍然可以使用In-Proc(关于In-Proc和Out-Proc的知识点补充)的模式和粘性(sticky)Session将一个web应用部署到多个服务器上(负载均衡器会将属于相同session的所有请求定向到单个服务器),你可能必须保留session数据和缓存数据的多个副本。比如,如果你将产品部署到由4台服务器组成的web
farm上,并且你保持session数据为In-Proc,那时一个请求到达一个已经包含缓存数据的机会是四分之一或25%,然而你如果在正确的地方使用了集中式缓存机制,那么为每个请求找到缓存条目的机会就是100%。这对于严重依赖缓存数据的web应用是至关重要的。

使用集中式缓存机制(像App Fabric或Redis)的另一个好处是对实际的产品实现主动缓存系统的能力。主动缓存机制可以用于在客户端请求一个条目之前就可以将最受欢迎的条目预加载到缓存中。如果你使用实际的数据源来管理缓存同步时,那么这会帮助你大幅地改善大数据驱动应用的性能。

创建Web Gardens

之前提到,在一个IO受限的web应用中包含了很多长时间运行的操作(如web服务的调用),此时你可能想尽可能地释放主线程。默认情况下,每个web应用运行在一个主线程下,该主线程为保持web站点存活(alive)负责,但不幸的是,当它太忙的时候,你的站点就变得不能响应了。给应用添加更多的“主线程”是一种办法,这是通过将更多的工作者进程添加到IIS下的Web站点来实现的。每个工作者进程都会包括一个单独的主线程,因此,如果一个主线程繁忙,还有另外的主线程来处理到来的请求。

拥有多个工作者进程会将你的web站点变成一个Web Garden,这要求你将Session和应用数据持久化到Out-Proc中(例如一个state server或者Sql Server)。

巧妙地使用缓存和懒加载

无需强调,如果你将经常访问的一点数据缓存到内存中,那么这会减少数据库和web服务的调用。正如之前所说,这对于IO受限的应用特别有帮助,当网站处于低负载时可能会造成不幸。

提高站点响应的另一种方式是使用懒加载。懒加载意味着应用里不会有确定的数据片,但是它知道数据在哪里。比如,如果web页面上有一个下拉列表,这意味着要显示一个产品列表,一旦页面加载完毕,不必从数据库中加载所有的产品。你可以在页面中添加一个jQuery函数,该函数可以在第一次下拉时填充下拉列表。你也可以在代码中的许多地方使用相同的技术,比如当使用Linq查询和CLR集合时。

不要在MVC视图中放C#代码

ASP.NET MVC视图会在运行时编译而不是在编译时,因此,如果在视图中包含了太多的C#代码,那么你的代码不会编译后放到dll文件中。这样做不仅有害于软件的可测试性,还会使web应用更慢,因为每个页面都有花更长的时间获得显示(因为它们必须被编译)。将代码添加到视图中的其他缺陷在于它们不能异步运行,这样,如果你决定基于TAP来构建应用时,就不能充分利用视图中的异步方法和action了。

比如,如果你的代码中有这么一个方法:

public async Task<string> GetName(int code)
{

    var result = …

    return await result;

}

该方法可以在一个异步的ASP.NET MVC action的上下文中异步运行,比如:

public Task<ActionResult> Index( CancellationToken ctx )
{
    var name = await GetName( 100 );
}

但是如果在一个视图中调用这方法,因为该视图不是异步的,所以必须以一种线程阻塞(thread-blocking)的方式运行,如:

var
name = GetName(100).Result;

.Result会阻塞运行的线程,直到GetName()处理完成了请求,这样该应用的执行会停止一会儿,然而当使用await关键字调用该代码时,该线程不会被阻塞。

适当时使用Fire & Forget

注:Fire & Forget,字面意思是发射,然后忘记,不去理会了。网络释义为射后不理。

如果两个或多个操作没有生成单个事务,那么你很可能不必按顺序运行它们。比如,如果一个用户在你的站点注册时创建了一个账户,一旦他们注册了,你就把他们的详细信息保存到数据库,然后给他们发送一封邮件,你不必等待邮件发送出去才结束这个操作。

在这种情况下,最好的方法很可能就是开启一个新的线程,让它给用户发送邮件,然后返回到主线程。这就叫做Fire& Forget,它可以提高应用的响应能力。

为x64 CPU创建

32-bit的应用局限于较低的内存量和可以访问更少的CPU功能/指令。要克服这些限制,如果你的服务器是64-bit的,那么要确保你的应用运行在64-bit模式下(通过确保在IIS的32-bit模式下运行网站的选项是不是开启)。然后为x64 CPU编译并生成代码而不是Any CPU。

x64有用的一个例子是提高数据驱动应用的响应能力和性能,有一个好的缓存机制是必须的。In-proc是消耗内存的,因为一切都存储在网站的应用程序池的内存边界。对于x86进程来说,可以分配的内存量限制到4GB,这样,如果加载到缓存中,这个限制很快就被打破。如果相同的站点是为x64 CPU显式生成的,那么内存限制就不需考虑了,这样更多的条目可以加到缓存中,然后和数据库的通讯就少了,这会带来更好的性能。

使用服务器上的监视和诊断工具

可能存在你肉眼看不到的更多的性能问题,因为它们不会出现在错误日志中。当应用程序已经部署到基本没有机会调试的服务器上时,识别性能问题是更吓人的事情。

要找出缓慢的处理,线程阻塞,悬挂,错误等等,强烈建议在服务器上安装一个监视和诊断工具,让它们持续地跟踪和监视你的应用程序。我个人使用的是NewRelic检查我的在线网站的健康。获取详细信息并创建免费账号看这里哦!

分析运行中的应用

一旦完成了网站开发,部署到IIS,然后附加一个分析器(如Visual Studio Profiler),然后抓取应用的多个部分的快照。比如抓取购买或者用户注册等操作的快照,然后检查病查看是否存在任何造成缓慢或阻塞的代码。在早期阶段找到那些热点可能会节省你大量的时间,荣誉和金钱。

翻译自:https://aspguy.wordpress.com/2014/02/17/building-high-performance-asp-net-applications/

感谢原作者 ASPGUY

扩展:asp.net
web应用如何测试性能及负载测试

时间: 2024-08-24 13:42:38

【给中高级开发者】构建高性能ASP.NET应用的几点建议的相关文章

【读书笔记】2016.12.10 《构建高性能Web站点》

本文地址 分享提纲: 1. 概述 2. 知识点 3. 待整理点 4. 参考文档 1. 概述 1.1)[该书信息] <构建高性能Web站点>: -- 百度百科 -- 本书目录: 第1章 绪论 1.1 等待的真相 1.2 瓶颈在哪里 1.3 增加带宽 1.4 减少网页中的HTTP请求 1.5 加快服务器脚本计算速度 1.6 使用动态内容缓存 1.7 使用数据缓存 1.8 将动态内容静态化 1.9 更换Web服务器软件 1.10 页面组件分离 1.11 合理部署服务器 1.12 使用负载均衡 1.1

Python Flask 快速构建高性能大型web网站项目实战

Python Flask 快速构建高性能大型web网站项目实战视频[下载地址:https://pan.baidu.com/s/1cUggNbUvptYz5vvwBhsdrg ] 作为最最流行的Python Web开发的微框架,Flask独树一帜.它不会强迫开发者遵循预置的开发规范,为开发者提供了自由度和创意空间.突然发现这个对自动化运维开发非常有用,发上来,给大家! Python Flask 快速构建高性能大型web网站项目实战视频 project.zip 第1章 课程介绍1.1-1.2课程导学

构建高性能数据库缓存之redis主从复制

一.什么是redis主从复制? 主从复制,当用户往Master端写入数据时,通过Redis Sync机制将数据文件发送至Slave,Slave也会执行相同的操作确保数据一致:且实现Redis的主从复制非常简单. 二.redis主从复制特点 1.同一个Master可以拥有多个Slaves. 2.Master下的Slave还可以接受同一架构中其它slave的链接与同步请求,实现数据的级联复制,即Master->Slave->Slave模式: 3.Master以非阻塞的方式同步数据至slave,这将

浅入深出ElasticSearch构建高性能搜索架构

浅入深出ElasticSearch构建高性能搜索架构  课程学习地址:http://www.xuetuwuyou.com/course/161 课程出自学途无忧网:http://www.xuetuwuyou.com 一.课程用到的软件 ElasticSearch5.0.0 Spring Tool Suite 3.8.2.RELEASE Maven3.0.5 Spring4 Netty4 Hadoop2.7.1 Kibana5.0 JDK1.8.0_111 二.课程目标 1.快速学习Elastic

构建高性能服务(三)Java高性能缓冲设计 vs Disruptor vs LinkedBlockingQueue--转载

原文地址:http://maoyidao.iteye.com/blog/1663193 一个仅仅部署在4台服务器上的服务,每秒向Database写入数据超过100万行数据,每分钟产生超过1G的数据.而每台服务器(8核12G)上CPU占用不到100%,load不超过5.这是怎么做到呢?下面将给你描述这个架构,它的核心是一个高效缓冲区设计,我们对它的要求是: 1,该缓存区要尽量简单 2,尽量避免生产者线程和消费者线程锁 3,尽量避免大量GC 缓冲 vs 性能瓶颈 提高硬盘写入IO的银弹无疑是批量顺序

《构建高性能 Web站点》笔记

书名:构建高性能Web站点 出版社: 电子工业出版社 ISBN:9787121170935 一  绪论 等待的时间: (1) 数据在网络上的传输时间 (2) 站点服务器处理请求并生成回应数据的时间 (3) 浏览器本地计算和渲染的时间 二  数据的网络传输 数据如何发送 (1) 应用程序通过系统函数库接口(如send)向内核发出系统调用 (2) 系统内核将数据从用户态内存区复制到由内核维护的内核缓冲区(这块地址空间的大小有限,需要发送的数据以队列的形式进入) (3) 内核通知网卡来取数据,网卡将数

NHibernate构建一个ASP.NET MVC应用程序

NHibernate构建一个ASP.NET MVC应用程序 什么是Nhibernate? NHibernate是一个面向.NET环境的对象/关系数据库映射工具.对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去. NHibernate 是一个基于.Net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Java的Hibernate 关系型持久化工具.

《构建高性能web站点》随笔 无处不在的性能问题

前言– 追寻大牛的足迹,无处不在的“性能”问题. 最近在读郭欣大牛的<构建高性能Web站点>,读完收益颇多.作者从HTTP.多级缓存.服务器并发策略.数据库.负载均衡.分布式文件系统多个方面娓娓道来,洋洋洒洒,甚是精彩,想来让人心旷神怡.     但“纸上得来终觉浅,绝知此事要躬行”,要消化本书的内容,绝不是一件简单的事情,更重要的还是实践.在实践和学习的过程中,我会把自己的经验和感悟分享出来,一方面权当做笔记,另一方面,对于后来的童鞋,希望能提供一丝一毫的帮助,不胜欣慰.     由于是读书

HAProxy + Keepalived + Flume 构建高性能高可用分布式日志系统

一.HAProxy简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代 理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理. HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接.并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上. 二.Keepalived简介 它是一个基于VRRP协议来实现的WEB服务高可用方案,