反应式Redis(Lettuce)始终发布到单线程

时间:2018-10-26 04:09:44

标签: spring-webflux lettuce reactor-netty

Im使用Spring Webflux(带有spring-reactor-netty)2.1.0.RC1和生菜5.1.1.RELEASE。

当我使用Reactive Lettuce API调用任何Redis操作时,执行总是切换到相同的单个线程(lettuce-nioEventLoop-4-1)。

由于所有执行都在该单个线程中成为瓶颈,因此导致性能下降。

我知道每次调用Redis切换到另一个线程时都可以使用publishOn,但这很容易出错,但仍然不是最佳选择。

有没有什么方法可以改善?我看到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 :(得分:2)

这是一个很好的问题!

TL; DR;

Lettuce始终使用绑定到netty通道的I / O线程进行发布。这可能适合或不适合您的工作量。

朗读

Redis是单线程的,因此保持单个TCP连接很有意义。 Netty的线程模型是,所有I / O工作均由绑定到通道的"ajax": "/Data.json", 线程处理。由于这个星座,您将在同一线程上接收所有反应性信号。使用带有各种选项的各种反应序列来基准化影响是有意义的。

不同的使用方案(即使用池连接)会直接改变观察结果,因为池使用不同的连接,因此在不同的线程上会收到通知。

另一种选择是提供EventLoop仅用于响应信号(数据,错误,完成)。在某些情况下,由于消除了I / O线程中的拥塞,可以忽略上下文切换的成本。在其他情况下,上下文切换成本可能会更高。

您已经可以通过WebFlux观察到相同的行为:每个传入连接都是一个新连接,因此它由不同的入站ExecutorService线程处理。在将HTTP响应写入通道时,重用同一EventLoop线程进行出站通知(那个用于入站通知的线程)发生的时间很晚。

这种双重职责(完成命令,执行I / O)可能会导致一些重担,而这会导致更多的计算量工作负载,从而将性能拖离I / O。

其他资源: