1

正如此处各种其他相关问题中所述,我还期望在(重新)部署具有相当大的 EF6 模型和大量引用的 nuget 包的 Web 角色后,第一次调用会持续很长时间(30 秒)。在尝试了不同的建议解决方案之后preloadEnabledserviceAutoStartProviders我仍然感到困惑并决定重新打开这个话题,希望有人在此期间找到更好的解决方案。

我的主要目标是让 Web 角色在新部署中退出其忙碌状态并可由负载均衡器和外部客户端访问时,几乎与后续调用一样快地响应第一个请求。不幸的是,到目前为止,我在提出的解决方案中遇到了以下问题:

  1. preloadEnabled

    • 我确实PKGMGR.EXE /iu:IIS-ApplicationInit在启动任务中添加了应用程序初始化模块。到目前为止,一切都很好。
    • 然后,当我尝试执行%windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true它时,它会失败,因为在执行启动脚本时仍然没有在 IIS 中创建新部署的网站。
    • 如果我尝试ServerManager在我的方法中通过 -class设置 preloadEnabled 设置Application_Start,我无法理解,在对 web 角色进行第一次外部调用之前,如何执行此代码,因为 preloadEnabled 设置默认为 false 之后一个新的网络角色部署,因此我理解的 Application_Start 方法没有机会被应用程序初始化模块执行?
  2. serviceAutostartProviders

    • 在这里,我们需要IProcessHostPreloadClient在 applicationhost.config 中放置实现接口的 AutostartProvider 的名称,即使用 appcmd 脚本或 ServerManager 类,但是:
      • serviceAutostartProvider 就像 preloadEnabled 一个与站点相关的设置,所以我们在这里遇到与%windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true1.2 中相同的问题 - 在全新部署后的启动脚本执行时,网站尚未在 IIS 中创建并且脚本无法正确执行
      • 另一种可能性是将 applicationhost.config 包含到部署包中,但我没有找到任何解决方案来为 Web 角色执行此操作。

那么你们是如何设法确保在角色第一次从外部受到攻击之前运行预加载程序集和一些初始化代码(如填充内存缓存)?

我们现在开始获得一些流量并获得大约。我们的 WebApi 上每秒有 1-2 个请求,因此在每次更新部署后预加载对客户端“可见”的 30 秒延迟现在已成为一个主要问题。

我们在低流量时间安排更新部署,但如果我需要进行紧急修补程序部署怎么办?

4

2 回答 2

1

实现这一点的最佳方法可能是使用部署槽。首先将更新部署到您的暂存槽。在从暂存槽切换到生产槽之前,Kudu 将向暂存槽的根发出请求以预热应用程序。在对暂存槽根的请求返回后,会发生 IP 切换并交换您的槽。

但是,有时您需要预热其他页面或服务以使应用程序准备好处理流量,并且通过预热请求访问根目录是不够的。您可以更新您的 web.config,以便 Kudu 在 IP 切换和插槽被交换之前访问其他页面和端点。

这些预热请求 URL 应该在标记中。这是一个例子:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <applicationInitialization>
      <add initializationPage="/pagetowarmup1" />
      <add initializationPage="/pagetowarmup2" />
      <add initializationPage="/pagetowarmup3" />
    </applicationInitialization>
  </system.webServer>
</configuration>

您可以在此处阅读有关此问题的 Kudu 文档。

于 2017-02-21T00:35:55.957 回答
0

好的。现在我知道了。

关键是不要在 Global.asax 中的方法内部设置preloadEnabled-property Application_Start(因为无论如何它不会在第一次请求 Role 之前被命中),而是在RoleEntryPoint.OnStart.

不同的是,RoleEntryPoint.OnStart部署包解压后直接调用,一切都设置好启动角色。此时,Azure 实例仍处于忙碌状态,只要 RoleEntryPoint.OnStart 中的某些代码正在执行,就无法从外部获得。

所以这是到目前为止我提出的用于在实例从外部第一次调用之前预热实例的代码

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        // set preloadEnabled of each Site in this deployment to true
        using (var serverManager = new ServerManager())
        {
            foreach (var mainSite in serverManager.Sites)
            {
                var mainApplication = mainSite.Applications["/"];
                mainApplication["preloadEnabled"] = true;
            }
            serverManager.CommitChanges();
        }

        // call my warmup-code which will preload caches and do some other time consuming preparation
        var localuri = new Uri(string.Format("https://{0}/api/warmup", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint1"].IPEndpoint));
        try
        {
            var request = (HttpWebRequest)WebRequest.Create(localuri);
            request.Method = "GET";
            var response = request.GetResponse();
        }
        catch { }

        // send this thread to sleep in order to give the warmup-request a chance to complete BEFORE the Role will get started 
        // and becomes available to the outside world
        System.Threading.Thread.Sleep(60000);


        return base.OnStart();
    }


}
于 2017-02-22T14:30:26.527 回答