Azure的Web角色压力测试 - 1000毫秒的AsyncController阻塞操作 [英] Azure Web Role Stress Test - 1000ms blocking operation in AsyncController

查看:168
本文介绍了Azure的Web角色压力测试 - 1000毫秒的AsyncController阻塞操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我想模拟等待来自在MVC3 Web角色一个AsyncController内长期运行阻断过程(5至30秒)。然而,开始,我刚开始用1秒,得到的东西去。是的,这种智慧是值得商榷的,因为阻塞操作目前不能被异步上我运行/ O完成端口到外部服务,但我想看到的性能极限是什么,这个特殊的情况。

Today, I wanted to simulate waiting for a long-running blocking process (5 to 30 seconds) from within an AsyncController in an MVC3 web role. However, to begin, I just started with 1 second, to get things going. Yes, the wisdom of this is questionable, since the blocking operation cannot currently be run asynchronously on an I/O Completion Port to an external service, but I wanted to see what the performance limit is for this particular situation.

在我的Web角色,我部署了6个小实例。唯一的控制器是一个AsyncController,有两个目的是模拟1000毫秒阻塞操作的简单方法。

In my web role, I deployed 6 small instances. The only controller was an AsyncController, with two simple methods intended to simulate a 1000ms blocking operation.

在MVC3 Web角色控制器是简单:

The MVC3 web role controller was simply this:

public class MessageController : AsyncController
{
    public void ProcessMessageAsync(string id)
    {
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(() => DoSlowWork());
    }

    public ActionResult ProcessMessageCompleted()
    {
        return View("Message");
    }

    private void DoSlowWork()
    {
        Thread.Sleep(1000);
        AsyncManager.OutstandingOperations.Decrement();
    }
}

接下来,我施加的压力,从Amazon EC2的Web角色。使用12台服务器,我憋足负荷慢慢向上,并得到了接近550请求/秒。推超出了任何企图遭到了明显的线程饥饿和后续错误。我认为我们打的CLR线程限制,我的理解是每个CPU 100个线程。搞清楚一些开销为AsyncController,并为1000ms的阻塞操作,平均每秒每台服务器六分之五百五十零= 92的请求似乎符合这一结论。

Next, I applied stress to the web role from Amazon EC2. Using 12 servers, I ramped the load up slowly, and got close to 550 requests/second. Any attempt to push beyond this was met with apparent thread starvation and subsequent errors. I assume that we were hitting the CLR thread limit, which I understand to be 100 threads per CPU. Figuring some overhead for the AsyncController, and an average of 550/6 = 92 requests per second per server for a 1000ms blocking operation seems to fit that conclusion.

这是真的吗?我看到其他人说类似的事情,在那里他们达到了每例如每秒60到80的请求与此类型的负载。此系统上的负荷将主要包括长时间运行的操作,每秒92所以在请求1000毫秒会一路下跌,当值为5000ms任务联机。

Is this for real? I have seen other people say similar things, where they reached 60 to 80 requests per second per instance with this type of load. The load on this system will be comprised mainly of longer-running operations, so 92 requests per second at 1000ms is going way down when the 5000ms tasks come online.

短,有没有办法超过每秒90左右的请求,在1000毫秒这种明显的限制,获得更高阻塞时间?我讲一些明显的错误在这里?

Short of routing the requests for the blocking I/O through multiple separate web role front ends to fan this load out to more cores, is there any way to get higher than this apparent limit of 90 or so requests per second at 1000ms block time? Have I made some kind of obvious error here?

推荐答案

我很抱歉,我不得不说这买,你已经被所有的博客声称,通过使用简单的 Task.Factory误导。 StartNew 是解决所有的问题,那么,它不是。

I'm sorry I have to say this buy you have been mislead by all the blogs claiming that by simply using Task.Factory.StartNew is the solution to all your problems, well, it's not.

采用以下负载测试我在你的code做了一下(我改变了睡眠10秒,而不是1秒,使事情变得更糟)。该测试模拟了200恒定用户共做2500的请求。而看看有多少失败的请求有因线程不足:

Take a look on the following load test I did on your code (I changed the sleep to 10 sec. instead of 1 sec. to make it even worse). The test simulates 200 constant users doing a total of 2500 requests. And look at how many failed requests there are due to thread starvation:

正如你所看到的,即使您使用的是带有AsyncController任务,线程饥饿仍在进行之中。难道是因为在长期运行过程中引起的?

As you can see, even if you're using an AsyncController with a Task, thread starvation is still happening. Could it be caused because of the long running process?

你知道,如果一个任务是长时间运行或没有你可以指定?看看这个问题:<一href=\"http://stackoverflow.com/questions/5295265/strange-behavior-when-i-dont-use-taskcreationoptions-longrunning\">Strange行为当我不使用TaskCreationOptions.LongRunning

Did you know you can specify if a task is long running or not? Take a look at this question: Strange Behavior When I Don't Use TaskCreationOptions.LongRunning

当你不使用LongRunning标志,任务计划在
  线程池的线程,而不是它自己的(专用)线程。这很可能是
  你的行为变化的原因 - 当你没有LongRunning标志在原地踏步,你可能得到线程池饥饿由于在过程中的其他线程

When you don't use the LongRunning flag, the task is scheduled on a threadpool thread, not its own (dedicated) thread. This is likely the cause of your behavioral change - when you're running without the LongRunning flag in place, you're probably getting threadpool starvation due to other threads in your process.

让我们看看如果我们改变1号线code会发生什么:

Let's see what happens if we change 1 line of code:

    public void ProcessMessageAsync(string id)
    {
        Task.Factory.StartNew(DoSlowWork, TaskCreationOptions.LongRunning);
        AsyncManager.OutstandingOperations.Increment();
    }

看看负载测试,多么大的变化!

Take a look at the load test, what a difference!

正如你所看到的,LongRunning选择似乎有很大的不同。让我们添加一些记录,看看内部发生:

As you can see, the LongRunning option seems to make a big difference. Let's add some logging to see what happens internally:

    public void ProcessMessageAsync(string id)
    {
        Trace.WriteLine(String.Format("Before async call - ThreadID: {0} | IsBackground: {1} | IsThreadPoolThread: {2} | Priority: {3} | ThreadState: {4}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground,
            Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.Priority, Thread.CurrentThread.ThreadState));
        Task.Factory.StartNew(DoSlowWork, TaskCreationOptions.LongRunning);
        AsyncManager.OutstandingOperations.Increment();
    }

    ...

    private void DoSlowWork()
    {
        Trace.WriteLine(String.Format("In async call - ThreadID: {0} | IsBackground: {1} | IsThreadPoolThread: {2} | Priority: {3} | ThreadState: {4}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground,
               Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.Priority, Thread.CurrentThread.ThreadState)); 
        Thread.Sleep(10000);
        AsyncManager.OutstandingOperations.Decrement();
    }

无LongRunning:

Before async call - ThreadID: 11 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background
Async call - ThreadID: 11 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background

随着Lo​​ngRunning:

Before async call - ThreadID: 48 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background
Async call - ThreadID: 48 | IsBackground: True | IsThreadPoolThread: False | Priority: Normal | ThreadState: Background

正如你所看到的,没有你实际使用的线程池中的线程,导致饥饿LongRunning。虽然LongRunning选项,在这种情况下的伟大工程,你必须不断的评估的,如果你真的需要它。

As you can see, without LongRunning you are actually using threads from the thread pool, causing the starvation. While the LongRunning option works great in this case, you should always evaluate if you really need it.

注意:由于您使用的Windows Azure,你需要考虑到负载平衡器将闲置几分钟后超时

Note: Since you're using Windows Azure, you need to take into account that the load balancer will timeout after a few minutes of inactivity.

这篇关于Azure的Web角色压力测试 - 1000毫秒的AsyncController阻塞操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆