Как долго функции Azure должны остыть, прежде чем они начнут масштабироваться? - PullRequest
0 голосов
/ 03 сентября 2018

В нашей среде разработки нашему приложению функций обычно требуется только пара серверов.

В выходные мы неожиданно вызвали цепную реакцию, которая привела к постепенному, непрерывному масштабированию до 140 серверов. Теперь, когда мы исправили основную проблему и очистили очереди, активность, похоже, нормализовалась. (Уф!)

Странно то, что (через 30 минут) у нас все эти серверы есть. Я ожидал бы, что они начнут отключаться довольно быстро, но вместо этого я вижу, что число «серверов в сети» колеблется (как вверх, так и вниз) между 110 и 140. Подавляющее большинство из них сидят там с 0 запросов / с, без процессора и без памяти.

Итак, несколько вопросов:

  • Ожидается ли это?
  • Какими эвристиками определяется количество серверов, которые подключены / находятся в сети?
  • Когда я должен ожидать, что это число вернется к уровням, к которым я привык?

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Просто чтобы добавить кое-что к тому, что написал @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), поэтому вы не можете получить полную картину, мы можем только догадываться (или спрашивать;))

0 голосов
/ 03 сентября 2018

Scale Controller - проприетарная технология с закрытым исходным кодом с недокументированным поведением. Официального ответа на ваш вопрос нет. Единственный способ ответить на него - сделать то, что вы сделали: провести эксперимент и измерить. Такое поведение может со временем измениться.

Функции имеют некоторую эвристику о том, когда масштабировать и когда масштабировать в зависимости от количества событий и использования ресурсов. В прошлом они были довольно скромными, но это не обеспечивало достаточно хороших темпов масштабирования. Теперь они склонны ошибаться при предоставлении слишком многих, а не слишком мало.

Хорошая новость заключается в том, что вы не должны заботиться о масштабировании, за исключением любопытства. Вы не платите за незанятые серверы.

...