代码之家  ›  专栏  ›  技术社区  ›  Tom Wright

Azure功能需要冷却多久才能扩展?

  •  2
  • Tom Wright  · 技术社区  · 6 年前

    在我们的开发环境中,我们的功能应用程序通常只需要几个服务器。

    上周末,我们意外地引发了一系列连锁反应,导致逐步、持续地扩展到大约140台服务器。现在我们已经解决了基本问题并清除了队列,活动似乎已经恢复正常。(呸!)

    奇怪的是(30分钟后)我们仍然有所有的服务器在线。我本以为他们会很快开始下线,但相反,我看到“在线服务器”的数量在110到140之间波动(上升和下降)。其中绝大多数都是0个请求/秒,没有CPU和内存。

    • 这是预期的吗?
    2 回复  |  直到 6 年前
        1
  •  2
  •   kamil-mrzyglod    6 年前

    我们可以查看源代码并尝试至少理解部分功能。实际上,它基于计时器和worker的概念,worker更新它们的状态,并让运行时决定是否需要放大或缩小。

    整体算法描述如下:

    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 ),所以你无法了解全貌,我们只能猜测(或询问;)

        2
  •  2
  •   Mikhail Shilkov    6 年前

    函数确实有一些启发式方法,可以根据均衡量和资源利用率来确定何时扩展和何时扩展。在过去,他们相当节俭,但这并没有提供足够好的扩张步伐。现在,他们倾向于在资源调配过多而不是过少方面犯错误。

    好消息是,除了出于好奇之外,你不应该真的关心扩展。你不用为闲置的服务器付费。