Как элегантно внедрить механизм повтора в бизнес-логику

задняя часть
Как элегантно внедрить механизм повтора в бизнес-логику

Автор|Тянь Ханг (Шпоры)

Зачем вводить механизм повторных попыток

Давайте сначала посмотрим на обычный процесс взаимодействия с бизнес-системой, как показано на рисунке ниже, разработанная нами система обращается к другим бизнес-системам через HTTP-интерфейс или через RPC, а другие системы возвращаются к нужным нам данным, статус — успех .

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

Такие неприятные проблемы приведут к тому, что система, которую мы сами поддерживаем, попадет в нестабильное состояние из-за сильной зависимости от бизнеса (конечно, такая сильная зависимость невозможна, ведь бизнес нужно отделять и самостоятельно развивать и поддерживать).

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

Конечно, есть еще несколько вопросов, которые необходимо рассмотреть после введения механизма повторных попыток.

  • Сколько раз мы должны повторить попытку?
  • Каков подходящий интервал для каждой повторной попытки?
  • Что делать, если все повторные попытки израсходованы и все еще безуспешны? Ниже мы анализируем эти вопросы.

Повторите попытку несколько раз.

Вообще говоря, ситуация, с которой мы сталкиваемся с одной повторной попыткой, аналогична той, что мы проанализировали выше, и существует большая неопределенность.Сколько раз является разумным количеством раз? Это требует «конкретного анализа конкретного бизнеса», но в целом 3 повторных попытки могут почти удовлетворить большинство потребностей бизнеса. Конечно, это необходимо обсудить в связи с интервалом между повторными попытками, который будет упомянут позже. Зачем говорить 3 раза в принципе достаточно, ведь если запрошенная система действительно долго недоступна. Нам не имеет смысла повторять несколько раз.

Каков подходящий интервал повтора

Если интервал повтора установлен слишком маленьким, мы можем снова вызвать до того, как вызываемая система успеет восстановиться, и результатом определенно будет Fail; если он установлен слишком большим, наша собственная система пожертвует большим количеством своевременности данных. Следовательно, интервал повтора также должен быть правильно оценен в соответствии со средним временем восстановления вызываемой системы.Вообще говоря, это среднее время восстановления трудно рассчитать, поэтому общее эмпирическое значение составляет от 3 до 5 минут.

Что мне делать, если я все еще терплю неудачу после использования возможности повторной попытки?

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

Здесь также необходимо рассмотреть очень важную проблему, а именно идемпотентность вызовов интерфейса.Если интерфейс не является идемпотентным, легко могут возникнуть проблемы, связанные с путаницей данных при повторных попытках вручную.

Инструментарий Spring Retry

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

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

Затем добавьте аннотацию @EnableRetry к классу запуска или классу конфигурации и добавьте аннотацию @Retryable к методу, который необходимо повторить.

@Retryable
public String hello(){
    long times = helloTimes.incrementAndGet();
    log.info("hello times:{}", times);
    if (times % 4 != 0){
        log.warn("发生异常,time:{}", LocalTime.now() );
        throw new HelloRetryException("发生Hello异常");
    }
    return "hello " + nameService.getName();
}

Для получения более подробной информации об использовании и свойствах обратитесь к документации Spring Retry, которая очень четко объяснена. Здесь следует отметить, что механизм повторных попыток Spring все еще имеет определенные недостатки: он поддерживает только захват исключений, но не может проверять возвращаемое значение.

Guava Retry

По сравнению с Spring Retry, Guava Retry обладает большей гибкостью и может определять необходимость повторной попытки в соответствии с проверкой возвращаемого значения. Нам все еще нужно сначала импортировать его зависимости.

<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>

Он также очень прост в использовании.Сначала создайте экземпляр Retryer, а затем используйте этот экземпляр для вызова метода, который необходимо повторить.Существует много способов установить механизм повтора, например, использовать retryIfException для повторения всех исключений, используя retryIfExceptionOfType используйте метод retryIfRuntimeException, чтобы повторить попытку указанного исключения, используйте retryIfResult, чтобы повторить попытку возвращаемого результата, который не соответствует ожиданиям, и используйте метод retryIfRuntimeException, чтобы повторить все RuntimeExceptions.

@Test
public void guavaRetry() {
    Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
        .retryIfExceptionOfType(HelloRetryException.class)
        .retryIfResult(StringUtils::isEmpty)
        .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
        .withStopStrategy(StopStrategies.stopAfterAttempt(3))
        .build();

    try {
        retryer.call(() -> helloService.hello());
    } catch (Exception e){
        e.printStackTrace();
    }
}

По сравнению со Spring, Guava Retry предоставляет несколько основных функций.

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

резюме

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

В нашей повседневной работе есть много «больших» бизнес-сценариев, которые требуют от нас концентрации на прорыве и обдумывании, но есть и много подобных «маленьких» моментов, в которые нам нужно вникнуть и понять, и мы подбадриваем друг друга.