如何提高网站性能

6

你好!

我在运行Windows 2008服务器上的IIS7。
在高峰时段,我们会出现以下行为:

  • CPU负载接近空闲
  • 请求排队(使用资源监视器进行监控)
  • 执行时间超过10秒

1-4) 请查看之前的版本和编辑

5) 异步执行任务

建议如下,我创建了一个简单的Web页面,并附带以下代码:

using System;
using System.Threading;
using System.Web;
using System.Web.UI;

namespace PerformanceTest
{
    public partial class AsyncPage : Page
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            var pageAsyncTask = new PageAsyncTask(this.BeginAsyncOperation, this.EndAsyncOperation, this.TimeoutAsyncOperation, null);
            this.RegisterAsyncTask(pageAsyncTask);
            // or
            //this.AddOnPreRenderCompleteAsync(this.BeginAsyncOperation, this.EndAsyncOperation);

            // this might be useful for doing cleanup or sth alike
            this.PreRenderComplete += HandlePreRenderComplete;
        }

        private void HandlePreRenderComplete(object sender, EventArgs e)
        {
            this.Trace.Write("HandlePreRenderComplete");
            this.Trace.Write(string.Format("managedThreadId #{0}", Thread.CurrentThread.ManagedThreadId));
        }

        private delegate void Sleep(int miliseconds);

        private IAsyncResult BeginAsyncOperation(object sender, EventArgs e, AsyncCallback asyncCallback, object state)
        {
            this.Trace.Write("BeginAsyncOperation");
            this.Trace.Write(string.Format("managedThreadId #{0}", Thread.CurrentThread.ManagedThreadId));

            var sleep = new Sleep(Thread.Sleep);
            return sleep.BeginInvoke(1000, asyncCallback, state);
        }

        private void EndAsyncOperation(IAsyncResult asyncResult)
        {
            this.Trace.Write("EndAsyncOperation");
            this.Trace.Write(string.Format("managedThreadId #{0}", Thread.CurrentThread.ManagedThreadId));
        }

        private void TimeoutAsyncOperation(IAsyncResult asyncResult)
        {
            this.Trace.Write("TimeoutAsyncOperation");
            this.Trace.Write(string.Format("managedThreadId #{0}", Thread.CurrentThread.ManagedThreadId));
        }
    }
}

似乎非常不错,对吧?实际上它没有改变任何东西,在强调超过30秒后,响应时间增加到8秒,CPU使用率接近0%。
6)更新machine.config文件。
<system.net>
    <connectionManagement>
        <add address="*" maxconnection="12" />
    </connectionManagement>
</system.net>
<system.web>
    <processModel autoConfig="true"
                  maxWorkerThreads="100"
                  maxIoThreads="100"
                  minWorkerThreads="50"
                  minIoThreads="50" />
    <httpRuntime minFreeThreads="88"
                 minLocalRequestFreeThreads="76" />

</system.web>

使用异步操作将有助于提高性能,因为线程将返回到请求池中,并且您将拥有更高的并行度。不过,这将意味着需要进行严格的重新编程。 - Mikael Östberg
@MikaelÖstberg 我知道 - 这就是为什么我编辑了我的问题。这只是一个简短的补救措施...当前高峰可能变得更糟 :( ... 异步页面将是实现此类页面的正确方法,但我不是创作者 - 只是修改者 :) - user57508
4个回答

3

我已经使用了一些设置 - 尽管没有使用线程。我猜你的问题是“我在哪里可以更改这个”;答案是“在machine.config中”。链接显示您需要更改哪些设置;我不确定这是否明智。我希望您能将N增加到更高的值,但是增加到N+1的后果可能比现在更糟糕... - Neville Kuyt

2
您正在使用一个页面,可能还有Session,因此由于Session的原因,每个页面加载都会锁定其他所有页面。因此,您可以将其称为Async,或者调用PageAsyncTask,但是由于Session的原因,页面会锁定所有其他调用,并且页面调用会排队执行。
仅供测试禁用Session,如果您不使用任何Session数据,请在此页面上保持其禁用状态。
另请参阅:完全替换ASP.Net的session Web Garder 您可以设置Web Garden,即为同一Web应用程序提供更多池。通过这样做,您需要重新检查所有代码并包括互斥锁或数据库锁的同步,因为使用两个或更多池时,可以通过不同的线程访问和写入相同的数据。 http://msdn.microsoft.com/en-us/library/aa479328.aspx

1

答案很简单:

不要阻塞线程

事实是,IIS 和 ASP.NET AppDomain 只能处理 N 个并发请求。你可以增加这个数量,但是对成千上万个同时运行的线程进行完全锁定会导致瓶颈噩梦。如果不知道是什么原因导致 ASP.NET 页面响应时间少于一秒,则很难建议任何性能调整,但是问题可能不在 IIS 中,而在代码中。

如果代码在几秒钟的时间内阻塞一个线程而实际上没有执行任何操作(如 CPU 使用情况所见),则存在某种 IO 操作速度非常慢,显然应该将其异步执行。如果这些请求不阻塞线程,Web 服务器可以处理几乎无限数量的并发请求(仅受可用硬件资源限制)。如果它们阻塞线程,则只能执行可用线程数的请求,这是一个严格的上限。

异步执行任务

重写你的代码,不要通过调用同步方法来锁定线程,而是使用它们的异步版本Begin...End...方法。Async CTP可以帮助你将这些Begin和End调用包装在看起来同步的代码中,但是即使没有async的东西,性能优势也非常巨大,所以你应该考虑重写任何导致页面锁定的代码。

事实是,IIS和ASP.NET AppDomain只能处理N个并发请求。在哪里可以调整此设置? - user57508
重写您的代码,以便通过调用Begin...和End...方法代替它们的同步相应方法来避免锁定线程。这样做将会打开一个新的线程来处理任务,是吗?AppDomain可以处理多少个线程? - user57508
谢谢你的回答!我想回复:如上所述,我已经使用Thread.Sleep()调整了我的代码,以确保执行时间为1秒(封闭范围)。因此,如果IIS可以处理N个请求(并处理它们),每个被积极处理的请求都不应该超过1秒(加上一些噪音...)。问题是,当进行多于N个请求时,它们会排队,执行时间为X(排队时间)+ 1秒。如果我能增加并发线程/请求的数量,就不会有问题 :) - user57508
2
仅仅增加并发线程的数量只能带你走得那么远。真正的问题在于每个请求在等待IO时都会锁定线程。与其锁定线程,Begin将释放线程,以便其他请求可以使用它,而End仅在准备好处理结果的纳秒时被调用。 - Asbjørn Ulsberg
我猜当你调用Begin...方法时,.NET框架在内部使用了WaitHandle,但这是我不熟悉的具体实现细节。 :-) - Asbjørn Ulsberg
谢谢您的意见,但请看我的编辑 :) ... 没有改变。 - user57508

1

我们曾经遇到过类似的问题。结果发现并不是我们的代码引起了问题。

在我们的情况下,问题出在 Windows 2008 R2 中的 TCP Chimney offload 上。Windows 2008 试图通过将工作卸载到网络卡上来变得更加聪明,但如果网络卡达到最大负荷,事情就会变慢,但所有正常的性能值都显示负载很小。

http://www.iislogs.com/steveschofield/troubleshooting-iis-7-network-performance-issues-and-tcp-chimney-offload-receive-side-scaling-and-network-direct-memory-access


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接