不可忽视的 .NET 应用5大性能问题_实用技巧

实现有效 APM 策略所面临的挑战:

  • 代码依赖
  • 过度或不必要的日志
  • 同步与锁
  • 潜在数据库问题
  • 潜在的基础架构问题

1、代码依赖

开发程序是一项具有挑战性的工作。你不仅要为了满足商业需求而建立程序逻辑,还要选择最合适的代码库和工具来帮助你。你能想象自己创建所有的日志管理代码,XML 和 JSON 解析逻辑,或所有的序列化库么?你当然可以编写代码来完成这些事,但是诸多开源开发者团队已经做好了这些事情,你又何必亲力亲为呢?此外,如果你正在与第三方系统集成,你会自己读完专有的通信协议规范,还是购买供应商提供的库帮你完成呢?

我相信你会同意:如果有人已经解决了你的问题,使用他的解决办法会比自己想办法解决效率更高。如果这是一个已经被许多公司采用的开源项目,那么很可能它已经经过完备的测试,文档充足,而且你应该找得到许多使用教程。

然而,使用依赖库是有危险的。你需要回答以下问题:

  • 这个库真的写得很好并且已经充分测试了吗?
  • 你是否用与众多公司一样的方式使用这个库?
  • 你的使用方式是否正确?

请确保在选择外部库之前进行一些调查,如果你对某个库的性能有什么疑问,那就进行一些性能测试。开源项目很好的地方在于你可以访问它们的全部源代码以及测试套件和构建流程。下载它们的源代码,执行编译过程,并查看测试结果。如果你看到很高的测试覆盖率,那么就可以比没有测试案例时信心百倍!

最后,确保正确地使用依赖库。如果正确使用,ORM 工具的确能够大大提高性能。ORM 工具的问题在于,如果你不花时间去学习如何正确地使用它,你就会轻易的砸自己脚,破坏自己的应用性能。关键就在于如果不花时间学习这些工具,本应帮助你的工具反而会伤害你。

2、过度或不必要的日志

日志记录是调试工具库里的强大武器,可以帮助你识别应用执行过程中在特定时间内可能发生的异常。当错误发生时,捕捉错误信息并收集尽可能多的上下文信息是非常重要的。然而,简洁地捕捉错误条件和过度记录之间是有差别的。

最普遍的两个问题就是:

  • 多级别异常日志
  • 错误配置生产日志级别

异常日志能帮助你了解应用程序中发生的问题,因而非常重要。但一个常见的问题是,应用程序所有层级的异常都进行记录。例如,你的某个数据访问对象捕获到一个数据库异常,并将该异常传达到服务层。服务层可能会捕捉该异常,并将其传达到网络层。如果我们在数据层、服务层和网络层上都记录该异常,那么我们对此相同的错误条件就有三条堆栈记录。这会导致写入日志文件的额外负担,还会使日志文件充满冗余信息。但这个问题非常普遍,我敢断言,如果你检查自己的日志文件,你很可能会发现多个这样的例子。

生产应用中常见的另一个大的日志问题与日志级别有关。.NET 日志记录器定义了以下日志记录级别(.NET TraceLevel 与 log4net 中的命名会有所不同,但绝对相似):

  • Off
  • Fatal
  • Error
  • Warning
  • Info
  • Verbose / Debug

在生产应用程序中,你应该只记录 error 或 fetal 级别的日志语句,在更宽松的环境中,捕捉 warning 甚至 info 级别的日志信息也完全可以,但是一旦应用投入生产环境,用户负载将迅速填满日志并使应用程序陷入瘫痪。如果你不经意地将生产环境下的应用日志级别设为 debug,应用的响应时间比正常情况下高两或三倍都不奇怪!

3、同步与锁

有时候,你想确保应用代码中每次只有一个线程执行一段代码子集。 例如,读取单线程规则执行组件之类的共享软件资源,以及文件句柄或网络连接之类的共享基础架构资源。.NET 框架提供了许多不同类型的同步策略,包括锁/监视器、进程间互斥,和读/写锁这类的专用锁。

不管你为什么要同步代码或者选择什么机制实现代码同步,都会导致一个问题:那就是有部分代码一次只能由一个线程执行。 设想去超市,只有一个收银员在工作:许多人进入商店,浏览商品,将商品放进购物车里,但某一时候,他们不得不排队以进行支付。在这个例子中,购物是多线程的,每个人都代表一个线程。然而结账是单线程的,这意味着每个人都要花费排队付款的时间。这个过程如图1所示。

 图1:线程同步

我们有七个线程,都需要访问一段同步代码块,所以它们依次获得权限访问该代码块,执行其功能,然后继续。

在图2中总结了线程同步的过程。 

图2 线程同步过程

首先,为特定的对象(System.Object 派生)创建锁,意味着当一个线程试图进入同步代码块时必须获取该同步对象的锁。如果该锁可用,则该线程被授予执行同步代码的权限。在图2中的例子中,当第二个线程到达时,第一个线程已经占有了该锁,所以第二个线程被强制等待,直到第一个线程执行完毕。当第一个线程执行结束时,会释放该锁,然后第二个线程被授予访问权限。

正如你可能猜测到的,线程同步将给 .NET 应用带来一个极大的挑战。我们设计应用程序时,希望其能支持数十个甚至数百个同步请求,但线程同步会把所有处理这些请求的线程串行化,导致性能瓶颈!

解决的办法有两种:

  • 仔细检查同步的代码,以确定是否存在其他可行办法
  • 限制同步代码块的范围

有时候,你要访问必须同步的共享资源,但很多时候,你可以用完全避免同步的方法重新解决该问题。例如,我们之前使用的规则过程引擎有单线程的要求,因此拖慢了程序中所有请求的执行速度。这显然是一个设计上的缺陷,我们可以用一个可以并行工作的库取代之。你需要问自己是否有更好的选择:如果你在往一个本地文件系统写入信息,你是否可以把信息发送给某项服务,再由该服务将信息存储到数据库中?你是否可以将对象设为不可变,从而无论是否有多线程访问它都没关系?等等,等等…

对于那些必须要同步的代码段,请合理地选择锁。你的目标是将同步代码块隔离以满足最低限度的同步要求。通常最好是定义一个特定的对象进行同步,而不是对包含同步代码的对象进行同步,因为你可能会在不经意间拖慢该对象的其他交互。最后,考虑使用读/写锁,而不是标准的锁,这样,你可以在资源只进行同步变化时,允许读操作。

4.潜在的数据库问题

几乎所有的内容应用最终都会涉及到向/从数据库或文档存储储存/检索数据。因此,数据库、数据库查询,以及存储过程调优对应用程序的性能来说是最重要的。

程序架构师/开发人员和数据库架构师/开发人员之间有一个哲学性的划分。应用程序架构师倾向于认为所有的业务逻辑都应该驻留在应用程序中,数据库应该只提供访问数据的通道。另一方面,数据库架构师更倾向于认为将业务逻辑推到数据库中更有益提高性能。这个划分的答案很可能就是介于两者之间。

作为一个应用程序架构师,我倾向于将更多的业务逻辑应用在程序当中,但我完全承认数据库架构师能更好的理解数据和与数据交互的最佳方式。我认为,这两个群体之间的协同合作才能产生最佳的解决方案。但是,不管你倾向于哪一方,请确保你的数据库架构师检查你的数据模型,所有的查询语句和存储过程,他们都有丰富的知识帮助你以最佳的方式来调整和配置数据库,他们有大量的工具可以为你调整查询语句。例如,有一些工具可用于 SQL 调优,遵循以下这些步骤:

  • 分析 SQL 语句
  • 确定查询的执行计划
  • 利用人工智能生成备选的 SQL 语句
  • 确定所有备选方案的执行计划
  • 提出最佳的查询方式来完成目标

当我在写数据库查询代码时,我使用了这类工具,并在高负载情况下量化了结果,一些细微的调整和优化,都能导致极大的性能提升。

5、潜在的基础架构问题

之前提过,.NET 应用运行在分层的环境中,其层级结构如图3所示:

 图3.NET分层执行模型

你的应用程序运行在 ASP.NET 或是 Windows Forms 容器中,使用 ADO 库与运行在 CLR 内部的数据库交互,而 CLR 运行在操作系统中,操作系统又运行在硬件里。而该硬件又与其他包含不同技术堆栈的硬件通过网络相连。在你的应用与外部环境之间,以及在应用的组件之间,通常有多个负载平衡器。我们还有 API 管理服务以及多级缓存。所有这一切,都是为了说明,基础构造数量庞杂,都可能影响应用程序的性能!

因此,你必须细致地调整基础架构。检查你的应用组件和数据库所运行的操作系统和硬件设备,以确保它们的最佳表现。测量服务器之间的网络延迟,并确保你有足够的带宽来满足应用程序之间的交互。检查缓存,确保较高的缓存命中率。分析负载平衡器的行为以确保请求很快地分发到所有可用的服务器。总之,你需要全面检查应用程序的性能,既包括应用业务交易也包括支持它们的基础架构。

时间: 2024-10-28 12:31:07

不可忽视的 .NET 应用5大性能问题_实用技巧的相关文章

ASP.NET Session会导致的性能问题_实用技巧

而且还是阵发性的,有某个用户投诉慢的时候,你访问却很快,本地又复现不出来?今天你访问了博客园真是太幸运了,也许这里就有你想要的一个答案--假如你的站点动态处理了图片或者其他原本不会动态处理的非网页资源的话.没想到吧,这是Session惹的祸! 我们公司某个站点访问量一直很大,几年前就已经发现客户经常投诉说很慢,而这个问题我们一直都在排查和解决.从线路问题,到数据库连接泄露,到数据库死锁.索引,以及程序的优化问题,我们都查找过,并且解决过.然而,这个问题总还是存在.比如说,在IIS日志中,就会经常

asp.ent(C#)中判断空字符串的3种方法以及性能分析_实用技巧

3种方法分别是: string a=""; 1.if(a=="") 2.if(a==String.Empty) 3.if(a.Length==0) 3种方法都是等效的,那么究竟那一种方法性能最高呢?本人用实验说明问题. 建立3个aspx页面(为什么用网页,主要是利用Microsoft Application Center Test ) WebForm1.aspx 复制代码 代码如下: private void Page_Load(object sender, Sys

asp.net 上传大文件解决方案_实用技巧

这次在项目中,用到了大文件上传,要上传的文件有100多m,于是研究现在国内使用的大文件上传的组件发现用的比较多的有两个控件AspnetUpload 2.0和Lion.Web.UpLoadModule,另外还有思归在它的博客堂中所说的办法 http://blog.joycode.com/saucer/archive/2004/03/16/16225.aspx   两个控件的方法是:利用隐含的HttpWorkerRequest,用它的GetPreloadedEntityBody 和 ReadEnti

asp.net小谈网站性能优化_实用技巧

当然,网站性能优化是多方面的,这里先谈一下这些天来的所获: 1.书写代码的习惯: 再复杂的逻辑,也是从最简单的开始.在书写代码的过程中,很多不好的规范都会影响网站的性能: 以下是整理出来的些许代码习惯: 1)字符串的比较 用 string.Empty 代替 " " 2)在遍历过程中,先定义好计数变量, 再遍历, 这样会减少每次遍历就分配一次内存空间: 复制代码 代码如下: int i; for( i=0; i<100;i++) { // codeing } 3)同样的,用 Str

分享提高ASP.NET Web应用性能的技巧_实用技巧

在这篇文章中,将介绍一些提高 ASP.NET Web 应用性能的方法和技巧.众所周知,解决性能问题是一项繁琐的工作,当出现性能问题,每个人都会归咎于编写代码的开发人员. 那性能问题到底该如何解决?以下是应用系统发布前,作为 .NET 开发人员需要检查的点. 1.debug=「false」 当创建 ASP.NET Web应用程序,默认设置为「true」.开发过程中,设置为「true」是非常有用多,但在应用程序发布部署时,需将其设置为「false」. <compilation defaultLang

Asp.Net性能优化技巧汇总_实用技巧

本文搜集汇总了Asp.net性能优化的各种技巧,对于Asp.Net开发人员有很好的参考借鉴价值.具体内容如下: 一.选择会话状态存储方式 在Webconfig文件配置: <sessionState mode="???" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"

解决.net项目中上传的图片或者文件太大无法上传问题_实用技巧

最近做项目的时候  用户提出要上传大图片  一张图片有可能十几兆  本来用的第三方的上传控件  有限制图片上传大小的设置  以前设置的是2M  按照用户的要求  以为直接将限制图片上传大小的设置改下就可以了  但是当上传大图片的时  总是异常: 错误消息:超过了最大请求长度 解决方案: 错误原因:asp.net默认最大上传文件大小为4M,运行超时时间为90S. 修改web.config中配置 <configuration> <system.web> <httpRuntime

关于VS2012自带的 性能分析 工具使用实例(图文介绍)_实用技巧

本篇通过一小段代码的console程序来进行性能的分析以及改进.直到后面的改进前.改进后性能比较结果. 先看console代码(源代码下载): 复制代码 代码如下: static void Main(string[] args)        {            int i = 10000;            while(i-->0)            {                Core c=new  Core();                c.Process(Dat

ASP.NET性能优化小结(ASP.NET&amp;amp;C#)_实用技巧

ASP.NET: 一.返回多个数据集 检查你的访问数据库的代码,看是否存在着要返回多次的请求.每次往返降低了你的应用程序的每秒能够响应请求的次数.通过在单个数据库请求中返回多个结果集,可以减少与数据库通信的时间,使你的系统具有扩展性,也可以减少数据库服务器响应请求的工作量. 如果用动态的SQL语句来返回多个数据集,那用存储过程来替代动态的SQL语句会更好些.是否把业务逻辑写到存储过程中,这个有点争议.但是我认为,把业务逻辑写到存储过程里面可以限制返回结果集的大小,减小网络数据的流量,在逻辑层也不