Разгрев веб-роли Azure после развертывания
Как описано в различных других связанных с этим вопросах здесь, я также ожидаю длительного (30 секунд) первого вызова после (пере) развертывания веб-роли с довольно большой моделью EF6 и множеством ссылочных пакетов nuget. После опробования различных предложенных решений с preloadEnabled
а также serviceAutoStartProviders
Я все еще изумлен и решил вновь открыть эту тему в надежде, что кто-то тем временем нашел лучшее решение.
Для меня главная цель - сделать так, чтобы веб-роль отвечала на первый запрос почти так же быстро, как и последующие вызовы, как только роль выйдет из своего занятого состояния при новом развертывании и станет доступной для балансировщика нагрузки и внешних клиентов. К сожалению, у меня возникли следующие проблемы с предлагаемыми решениями:
preloadEnabled
:- Я добавляю модуль инициализации приложения через
PKGMGR.EXE /iu:IIS-ApplicationInit
в задаче запуска. Все идет нормально. - Когда я тогда пытаюсь выполнить
%windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true
он завершается сбоем, так как на момент выполнения сценария запуска все еще не было сайтов, созданных в IIS при новом развертывании. - Если я попытаюсь установить preloadEnabled-параметр через
ServerManager
-класс в моемApplication_Start
Вместо этого, я не могу понять, как этот код должен выполняться перед первым внешним вызовом веб-роли, поскольку для параметра preloadEnabled по умолчанию задано значение false после развертывания новой веб-роли, и, таким образом, метод Application_Start в моем понимании не получить шанс быть выполненным модулем инициализации приложения?
- Я добавляю модуль инициализации приложения через
serviceAutostartProviders
:- здесь нам нужно указать имя нашего AutostartProvider, реализующего
IProcessHostPreloadClient
интерфейс в applicationhost.config, т. е. с помощью сценария appcmd или класса ServerManager, НО:- serviceAutostartProvider похож на preloadEnabled параметр, связанный с сайтом, поэтому у нас та же проблема, что и с
%windir%\system32\inetsrv\appcmd set site "MySiteName" -applicationDefaults.preloadEnabled:true
в 1.2 - во время выполнения сценария запуска после нового развертывания веб-сайты еще не созданы в IIS и сценарий не выполняется должным образом - Другой возможностью было бы включить applicationhost.config в пакет развертывания, но я не нашел никакого решения сделать это для веб-роли.
- serviceAutostartProvider похож на preloadEnabled параметр, связанный с сайтом, поэтому у нас та же проблема, что и с
- здесь нам нужно указать имя нашего AutostartProvider, реализующего
Итак, как вам удалось обеспечить предварительную загрузку сборок и некоторого кода инициализации (например, заполнение кэшей памяти) до того, как роль получит свой первый удар извне?
Мы начинаем набирать трафик сейчас и получаем ок. 1-2 запроса в секунду на нашем WebApi и, следовательно, 30-секундная задержка для предварительной загрузки, "видимой" для клиентов после каждого развертывания обновлений, становится серьезной проблемой.
Мы планируем развертывание обновлений при низком времени трафика, но что, если мне нужно срочно развернуть исправление?
2 ответа
Возможно, лучший способ сделать это - использовать слоты для развертывания. Сначала разверните обновления в своем промежуточном слоте. Перед переключением с промежуточного слота на рабочий слот 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 по этому вопросу здесь.
ХОРОШО. Теперь я понимаю.
Дело в том, чтобы установить preloadEnabled
-собственность не внутри Application_Start
метод в Global.asax (так как он все равно не будет обработан перед первым запросом к роли), но внутри 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();
}
}