ASP.NET MVC4页面在Microsoft Azure上加载速度极慢

时间:2017-12-20 16:46:58

标签: asp.net performance azure asp.net-mvc-4 azure-web-sites

在将ASP.NET MVC4应用程序部署到Microsoft Azure之后,我正在处理非常烦人的性能问题。在重新启动应用程序后(或在几分钟不活动后),一些页面第一次加载大约需要15秒。在此之后,即使在清除客户端缓存时,这些页面也会在大约2秒内加载(这仍然需要改进,但优于15秒,这是一个巨大的用户体验杀手)。

这是我到目前为止已经尝试过的内容:

  • 我梳理了Global.asax中的每个事件,以便用虚拟代码替换与数据库相关的代码
  • 将发布设置更改为:«发布期间预编译»(将所有输出合并到单个程序集)
  • 根据Azure的“应用程序性能分析”,我的应用程序被认为是“健康的”
  • «Always On»在门户网站的应用程序设置中激活(定价层为B1 [基本,1核心,1.75GB RAM],因此我假设永远在线的交换机不会被共享运行时覆盖配置)

由于以上没有一个子弹解决了我的问题,我尝试使用Quartz.NET写一个keppalive-Job,定期请求网站:

new System.Net.WebClient().OpenRead("https://foo.azurewebsites.net");

(在我的情况下,我认为效果或多或少与在Web.Config中声明initializationPages一样here,不是吗?)

结果:它有效,但仅适用于此特定网址。保持每个可能路线的清单肯定不是要走的路。

你有没有处理过这个问题?我非常感谢您的投入!

2 个答案:

答案 0 :(得分:3)

自从我在一个托管在azure上的组织工作已经有一段时间了,但他们曾经有一个选项,你可以配置标记为" Always On"这实际上相当于在应用程序池上将空闲超时设置为零并将应用程序加载到内存中。如果没有流量,那么您的站点将被卸载并在首次命中时被强制转换为JIT(有点像初始部署后)。

我已经读过其他人为他们的网站创建模拟http请求以保持流量上升并避免在他们订阅价格较低的层级时从内存中卸载,这些层级不提供"始终在& #34;选项。

编辑:这是另一篇SO帖子:App pool timeout for azure web sites

答案 1 :(得分:1)

除了接受的答案之外,我还想详细解释我是如何最终处理这个问题的。也许这可能在将来帮助别人。 我写了一些代码,通过简单地在关键站点上触发Web请求来启动应用程序(我已经获得了每个页面需要完成的经验。只是预热根地址是不够的)。

private void WarmUp()
{
  var baseUrl = "https://foo.azurewebsites.net";

  /**
   * Requests to protected pages need to be authenticated and authorized, otherwise the JIT-Compile won't work
   * For ASP.NET apps that are using FormsAuthentication just send a POST-request as you normally would do using a html form,
   * then grab the cookie you get in the response and pass it to the subsequent requests
   * */
  var email = "warmup.worker@foo.com";
  var password = "verysecure";
  var cookies = new CookieContainer();

  var webRequest = WebRequest.Create($"{baseUrl}/Account/Login") as HttpWebRequest;
  webRequest.Method = "POST";
  webRequest.ContentType = "application/x-www-form-urlencoded";
  webRequest.CookieContainer = cookies;

  var requestWriter = new StreamWriter(webRequest.GetRequestStream());
  requestWriter.Write($"user={email}&password={password}");//Small example for brevity. Don't forget to extract the requestVerificationToken in production :-)
  requestWriter.Close();
  webRequest.GetResponse().Close();

  var urls = new[] {
    baseUrl,
    $"{baseUrl}/Home/Contact",
    $"{baseUrl}/Protected/Stuff",
    //...
  };
  foreach (var url in urls)//trigger web-requests
  {
    webRequest = WebRequest.Create(url) as HttpWebRequest;
    webRequest.CookieContainer = cookies;
    webRequest.GetResponse().Close();
  }
}

这会在应用程序启动时/部署后触发耗时的JIT内容,从而阻止我们的用户在请求页面时遇到可怕的性能。如果您的应用的定价计划为S1或更高,则可以使用deployment slots进一步提高性能。它们允许您在部署到生产之前预热应用程序。

在我的情况下(保留定价层,B1),我认为在Application_Start中运行上面的代码就足够了,因为«Always on»应该阻止我的应用程序的工作进程自动关闭,以防网站没有' t在一段时间内获得任何流量(如果您的应用程序在共享资源上运行,请确保使用Cron作业或类似工具保持您的应用程序存活)。