После дросселирования вы можете повторить попытку с экспоненциальной задержкой

алгоритм

1. Предпосылки

Эта статья была одновременно опубликована вПубличный аккаунт Prodesire,а такжеБлог Prodesire. Недавно в процессе выполнения проекта тестирования API облачных служб я обнаружил, что иногда API вызывается в больших количествах, что приводит к ошибке ограничения тока. При обнаружении такого рода ошибок традиционная стратегия повторных попыток заключается в повторных попытках время от времени. Однако, поскольку он повторяется в фиксированное время, одновременно при повторной попытке будет поступать большое количество запросов, что будет постоянно вызывать ограничение тока.

Это напоминает мне о поиске два года назадДокументация по задачам сельдереяКогда я обнаружил, что могу установить его для задачиretry_backoffопыт, который позволяет выполнять задачи с指数退避способ повторить попытку. Итак, как именно выглядит экспоненциальная отсрочка?

2. Экспоненциальный откат

Согласно викиExponential backoffОбъяснение: экспоненциальная отсрочка — это алгоритм, который экспоненциально снижает скорость процесса с помощью обратной связи, чтобы постепенно найти подходящую скорость.

В Ethernet этот алгоритм обычно используется для запланированных повторных передач после коллизий. Отложенная повторная передача определяется на основе временного интервала и количества попыток повторной передачи.

существуетcПосле коллизии (например, неудачного запроса) в качестве количества слотов выбирается случайное значение от 0 до $2^c-1$.

  • Для первой коллизии каждый отправитель будет ждать 0 или 1 временной интервал для отправки.
  • И после 2-го столкновения отправитель будет ждать от 0 до 3 (рассчитывается как $ 2 ^ 2-1 $) временных интервалов для отправки.
  • И после 3-го столкновения отправитель будет ждать от 0 до 7 (рассчитывается как $ 2 ^ 3-1 $) временных интервалов для отправки.
  • И так далее...

По мере увеличения количества повторных передач степень задержки возрастает экспоненциально.

Проще говоря, временной интервал между каждой повторной попыткой в ​​два раза превышает предыдущий.

3. Ожидаемое значение экспоненциального отката

Математическое ожидание времени отсрочки — это среднее значение всех возможностей при равномерном распределении времени отсрочки. То есть вcПосле коллизий количество слотов отсрочки равно[0,1,...,N], где $N=2^c-1$ , то математическое ожидание времени отсрочки (в тайм-слотах) равно

?E(c)=frac{1}{N+1}sum_{i=0}^{N}{i}=frac{1}{N+1}frac{N(N+1)}{2}=frac{N}{2}=frac{2^c-1}{2}?

Итак, для предыдущего примера:

  • После первого столкновения ожидаемое время задержки составляет $E(1)=frac{2^1-1}{2}=0,5$.
  • После второго столкновения ожидаемое время задержки равно $E(2)=frac{2^2-1}{2}=1,5$.
  • После третьего столкновения ожидаемое время задержки равно $E(3)=frac{2^3-1}{2}=3,5$.

В-четвертых, применение экспоненциальной отсрочки

4.1 Экспоненциальный алгоритм отсрочки в Celery

посмотриcelery/utils/time.pyФункция для получения экспоненциального времени отсрочки:

def get_exponential_backoff_interval(
    factor,
    retries,
    maximum,
    full_jitter=False
):
    """Calculate the exponential backoff wait time."""
    # Will be zero if factor equals 0
    countdown = factor * (2 ** retries)
    # Full jitter according to
    # https://www.awsarchitectureblog.com/2015/03/backoff.html
    if full_jitter:
        countdown = random.randrange(countdown + 1)
    # Adjust according to maximum wait time and account for negative values.
    return max(0, min(maximum, countdown))

здесьfactor— коэффициент отсрочки, который влияет на общее время отсрочки. а такжеretriesсоответствует вышеуказанномуc(то есть количество столкновений). основной контентcountdown = factor * (2 ** retries)Это та же идея, что и алгоритм экспоненциальной отсрочки, упомянутый выше. Исходя из этого,full_jitterУстановить какTrue, смысл в том, чтобы сделать "джиттер" на время отсрочки, чтобы иметь некую случайность. Наконец, это ограничение заданного значения, чтобы оно не превышало максимальное значение.maximum, чтобы избежать бесконечного времени ожидания. Однако после достижения максимального времени отсрочки это может привести к повторному одновременному выполнению нескольких задач. узнать большеTask.retry_jitter.

4.2 Пример подключения в "Расширенном программировании в среде UNIX"

В главе 16.4 Advanced Programming in the UNIX Environment, 3-е издание, также есть пример использования экспоненциальной отсрочки для установления соединения:

#include "apue.h"
#include <sys/socket.h>

#define MAXSLEEP 128

int connect_retry(int domain, int type, int protocol,
                  const struct sockaddr *addr, socklen_t alen)
{
    int numsec, fd;

    /*
    * 使用指数退避尝试连接
    */
    for (numsec = 1; numsec < MAXSLEEP; numsec <<= 1)
    {
        if (fd = socket(domain, type, protocol) < 0)
            return (-1);
        if (connect(fd, addr, alen) == 0)
        {
            /*
            * 连接接受
            */
            return (fd);
        }
        close(fd);

        /*
        * 延迟后重试
        */
        if (numsec <= MAXSLEEP / 2)
            sleep(numsec);
    }
    return (-1);
}

В случае сбоя соединения процесс приостанавливается на короткое время (numsec), затем перейдите к следующему циклу и повторите попытку. Каждый цикл спит в два раза дольше, чем предыдущий, до максимальной задержки более 1 минуты, после чего он больше не будет пытаться.

Суммировать

Возвращаясь к вопросу в начале, при обнаружении ошибки ограничения тока мы можем повторить попытку с помощью алгоритма экспоненциальной отсрочки, и мы можем снова избежать ограничения тока в наибольшей степени. По сравнению с повторными попытками с фиксированным временем экспоненциальная отсрочка добавляет увеличение времени и случайность, делая ее более «умной». На данный момент нам больше не нужно беспокоиться о том, что ограничение тока прервет всю тестовую программу~