在我们的开发环境中,我们的功能应用程序通常只需要几台服务器。
在周末,我们意外地引发了连锁反应,导致逐步,持续扩展到大约140台服务器。现在我们已经修复了底层问题并清除了队列,活动似乎已恢复正常。 (唷!)
奇怪的是(30分钟后)我们仍然拥有所有这些服务器在线。我希望他们能够很快开始下线,但我看到“在线服务器”的数量在大约110到140之间波动(上升和下降)。其中绝大多数都坐在那里0个请求/秒,没有CPU,没有内存。
所以,有些问题:
只是添加一些@Mikhail所写的内容 - 你的函数比例如何取决于所用触发器的类型。如果使用队列,运行时将查看队列长度并根据消息数量向上/向下扩展。使用Event Hub,这种行为取决于集线器中的分区数量 - 您拥有的越多,就越渴望扩展您的功能。
可以查看源代码并尝试理解至少部分功能。实际上,它基于计时器和工作者的概念,它们更新状态并让运行时决定是否需要向上或向下扩展。
整体算法描述如下:
protected virtual async Task MakeScaleDecision(string activityId, IWorkerInfo manager)
{
if (DateTime.UtcNow < _scaleCheckUtc)
{
return;
}
try
{
var workers = await _table.ListNonStale();
_tracer.TraceInformation(activityId, manager, workers.GetSummary("NonStale"));
if (await TryRemoveIfMaxWorkers(activityId, workers, manager))
{
return;
}
if (await TryAddIfLoadFactorMaxWorker(activityId, workers, manager))
{
return;
}
if (await TrySwapIfLoadFactorMinWorker(activityId, workers, manager))
{
return;
}
if (await TryAddIfMaxBusyWorkerRatio(activityId, workers, manager))
{
return;
}
if (await TryRemoveIfMaxFreeWorkerRatio(activityId, workers, manager))
{
return;
}
if (await TryRemoveSlaveWorker(activityId, workers, manager))
{
return;
}
}
catch (Exception ex)
{
_tracer.TraceError(activityId, manager, string.Format("MakeScaleDecision failed with {0}", ex));
}
finally
{
_scaleCheckUtc = DateTime.UtcNow.Add(_settings.ScaleCheckInterval);
}
}
更重要的是,你可以在源代码中找到为什么你看到活着的工人的答案:
protected virtual async Task PingWorker(string activityId, IWorkerInfo worker)
{
// if ping was unsuccessful, keep pinging. this is to address
// the issue where site continue to run on an unassigned worker.
if (!_pingResult || _pingWorkerUtc < DateTime.UtcNow)
{
// if PingWorker throws, we will not update the worker status
// this worker will be stale and eventually removed.
_pingResult = await _eventHandler.PingWorker(activityId, worker);
_pingWorkerUtc = DateTime.UtcNow.Add(_settings.WorkerPingInterval);
}
// check if worker is valid for the site
if (_pingResult)
{
await _table.AddOrUpdate(worker);
_tracer.TraceUpdateWorker(activityId, worker, string.Format("Worker loadfactor {0} updated", worker.LoadFactor));
}
else
{
_tracer.TraceWarning(activityId, worker, string.Format("Worker does not belong to the site."));
await _table.Delete(worker);
_tracer.TraceRemoveWorker(activityId, worker, "Worker removed");
throw new InvalidOperationException("The worker does not belong to the site.");
}
}
不幸的是,实现的某些部分是密封的(如IWorkerInfo
),所以你无法得到全貌,我们只能猜测(或问;))
Scale Controller是一种具有无证行为的封闭源专有技术。您的问题没有正式答案。回答它的唯一方法就是做你做的事:运行实验和测量。但是,这种行为可能会随着时间的推
函数确实具有一些启发式,可以根据平均数量和资源利用率进行扩展以及何时扩展。在过去,他们非常节俭,但没有提供足够好的扩展速度。现在,他们倾向于错误配置太多而不是太少。
好消息是除了出于好奇之外,你不应该真正关心扩展。您不需要为空闲服务器付费。