Reactive Redis (салат) всегда публикуется в одном потоке - PullRequest
0 голосов
/ 26 октября 2018

Я использую Spring Webflux (с spring-реактор-нетто) 2.1.0.RC1 и Lettuce 5.1.1.RELEASE.

Когда я вызываю любую операцию Redis с использованием API Reactive Lettuce, выполнение всегда переключается натот же отдельный поток (lettuce-nioEventLoop-4-1).

Это ведет к снижению производительности, поскольку все выполнение становится узким местом в этом отдельном потоке.

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

Есть ли способ улучшить это?Я вижу, что Lettuce предоставляет класс ClientResources для настройки распределения потоков, но я не смог найти какой-либо способ интегрировать это с Spring webflux.

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

Я добавляю этот фрагмент одноклассного весеннего запуска, который можно использовать для воспроизведения того, что я описываю:

@SpringBootApplication
public class ReactiveApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReactiveApplication.class, args);
    }
}

@Controller
class TestController {

    private final RedisReactiveCommands<String, String> redis = RedisClient.create("redis://localhost:6379").connect().reactive();

    @RequestMapping("/test")
    public Mono<Void> test() {
        return redis.exists("key")
            .doOnSubscribe(subscription -> System.out.println("\nonSubscribe called on thread " + Thread.currentThread().getName()))
            .doOnNext(aLong -> System.out.println("onNext called on thread " + Thread.currentThread().getName()))
            .then();
    }

}

Если я продолжу вызывать конечную точку /test, я получу следующий вывод:

onSubscribe called on thread reactor-http-nio-2
onNext called on thread lettuce-nioEventLoop-4-1

onSubscribe called on thread reactor-http-nio-3
onNext called on thread lettuce-nioEventLoop-4-1

onSubscribe called on thread reactor-http-nio-4
onNext called on thread lettuce-nioEventLoop-4-1

1 Ответ

0 голосов
/ 26 октября 2018

Это отличный вопрос!

TL; DR;

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

Более продолжительное чтение

Redis является однопоточным, поэтому имеет смысл сохранить одно TCP-соединение.Модель потоков Netty заключается в том, что вся работа ввода-вывода обрабатывается потоком EventLoop, связанным с каналом.Из-за этого созвездия вы получаете все реактивные сигналы в одном потоке.Имеет смысл сравнить воздействие, используя различные реактивные последовательности с различными вариантами.

Другая схема использования (т. Е. Использование объединенных соединений) - это то, что напрямую изменяет наблюдаемые результаты, так как в пуле используются разные соединения и поэтому уведомления принимаются в разных потоках.

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

Вы уже можете наблюдать такое же поведение с WebFlux: каждое входящее соединение является новым соединением, и поэтому оно обрабатывается другим входящим потоком EventLoop.Повторное использование того же потока EventLoop для исходящих уведомлений (тот, который использовался для входящих уведомлений) происходит довольно поздно при записи HTTP-ответа на канал.

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

Дополнительные ресурсы:

...