Реактивный redis (салат-латук) всегда публикуется в одном потоке

Я использую Spring Webflux (с spring -actor-netty) 2.1.0.RC1 и Lettuce 5.1.1.RELEASE.

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

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

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

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

Кроме того, не будет ли опасно нынешнее поведение для нерадивого разработчика? Может, стоит немного подправить настройки по умолчанию. Я полагаю, что идеальным сценарием было бы, если бы салат-латук мог просто повторно использовать тот же цикл событий из 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
5
0
1 770
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

TL; DR;

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

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

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

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

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

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

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

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

Другие вопросы по теме