Reactive Redis(Lettuce)总是发布到单线程
Reactive Redis (Lettuce) always publishing to single thread
我正在使用 Spring Webflux(带有 spring-reactor-netty)2.1.0.RC1 和 Lettuce 5.1.1.RELEASE.
当我使用 Reactive Lettuce 调用任何 Redis 操作时 API 执行总是切换到同一个单独的线程 (lettuce-nioEventLoop-4-1)。
这导致性能不佳,因为所有执行都在该单个线程中遇到瓶颈。
我知道我可以在每次调用 Redis 时使用 publishOn
来切换到另一个线程,但这很容易出错并且仍然不是最优的。
有什么办法可以改善吗?我看到 Lettuce 提供了 ClientResources class 来自定义线程分配,但我找不到任何方法将其与 Spring webflux 集成。
此外,当前的行为对于粗心的开发人员来说不是很危险吗?也许默认值应该稍微调整一下。我想理想的情况是 Lettuce 可以重用来自 webflux 的相同事件循环。
我正在添加这个 spring 引导单曲 class 片段,可用于重现我所描述的内容:
@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
这是一个很好的问题!
TL;DR;
Lettuce 始终使用绑定到 netty 通道的 I/O 线程发布。这可能适合也可能不适合您的工作量。
阅读时间更长
Redis 是单线程的,因此保持单个 TCP 连接是有意义的。 Netty 的线程模型是所有 I/O 工作都由绑定到通道的 EventLoop
线程处理。由于这个星座,您会在同一个线程上收到所有反应信号。使用具有各种选项的各种反应序列来衡量影响是有意义的。
不同的使用方案(即使用池连接)会直接改变观察到的结果,因为池使用不同的连接,因此在不同的线程上收到通知。
另一种选择可能是为响应信号(数据、错误、完成)提供 ExecutorService
。在某些情况下,由于 I/O 线程中的拥塞消除,上下文切换的成本可以忽略不计。在其他情况下,上下文切换成本可能更显着。
您已经可以观察到与 WebFlux 相同的行为:每个传入连接都是一个新连接,因此它由不同的入站 EventLoop
线程处理。在将 HTTP 响应写入通道时,将相同的 EventLoop 线程重新用于出站通知(那个用于入站通知的线程)发生得相当晚。
这种责任的双重性(完成命令,执行 I/O)可能会导致计算量更大的工作负载,从而拖累性能 I/O。
其他资源:
我正在使用 Spring Webflux(带有 spring-reactor-netty)2.1.0.RC1 和 Lettuce 5.1.1.RELEASE.
当我使用 Reactive Lettuce 调用任何 Redis 操作时 API 执行总是切换到同一个单独的线程 (lettuce-nioEventLoop-4-1)。
这导致性能不佳,因为所有执行都在该单个线程中遇到瓶颈。
我知道我可以在每次调用 Redis 时使用 publishOn
来切换到另一个线程,但这很容易出错并且仍然不是最优的。
有什么办法可以改善吗?我看到 Lettuce 提供了 ClientResources class 来自定义线程分配,但我找不到任何方法将其与 Spring webflux 集成。
此外,当前的行为对于粗心的开发人员来说不是很危险吗?也许默认值应该稍微调整一下。我想理想的情况是 Lettuce 可以重用来自 webflux 的相同事件循环。
我正在添加这个 spring 引导单曲 class 片段,可用于重现我所描述的内容:
@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
这是一个很好的问题!
TL;DR;
Lettuce 始终使用绑定到 netty 通道的 I/O 线程发布。这可能适合也可能不适合您的工作量。
阅读时间更长
Redis 是单线程的,因此保持单个 TCP 连接是有意义的。 Netty 的线程模型是所有 I/O 工作都由绑定到通道的 EventLoop
线程处理。由于这个星座,您会在同一个线程上收到所有反应信号。使用具有各种选项的各种反应序列来衡量影响是有意义的。
不同的使用方案(即使用池连接)会直接改变观察到的结果,因为池使用不同的连接,因此在不同的线程上收到通知。
另一种选择可能是为响应信号(数据、错误、完成)提供 ExecutorService
。在某些情况下,由于 I/O 线程中的拥塞消除,上下文切换的成本可以忽略不计。在其他情况下,上下文切换成本可能更显着。
您已经可以观察到与 WebFlux 相同的行为:每个传入连接都是一个新连接,因此它由不同的入站 EventLoop
线程处理。在将 HTTP 响应写入通道时,将相同的 EventLoop 线程重新用于出站通知(那个用于入站通知的线程)发生得相当晚。
这种责任的双重性(完成命令,执行 I/O)可能会导致计算量更大的工作负载,从而拖累性能 I/O。
其他资源: