问题描述
我正在开发一个包含大约 6 万行代码的大型 Spring Boot 服务。它为每个传入请求调用大约 10 个依赖项到其单个端点。设置了断路器、超时和指标。
该服务不擅长管理困难的依赖关系。一旦他们的响应时间变长,服务就需要更多的 cpu,其延迟就会增加。这很糟糕,因为我们有一个延迟 SLO。
我们已经对 WebFlux 进行了实验,原型看起来非常有前途。现在我们要迁移。
解决这个大项目的一种方法是一个接一个地迁移依赖项。我们可以将它们重写为 Mono<>
,然后使用 block()
调用它们。该项目可以立即再次部署。像这样迁移完所有依赖后,将引擎从MVC切换到WebFlux,然后重写RestController
以及其间的所有代码。这可行,但理想情况下,我们希望在迁移第一个依赖项后立即看到性能优势。
是否可以在项目中添加一个 WebFlux 事件循环,在单独的线程中运行它并将依赖项一个一个地迁移到其中?那会是什么样子?目前,我们使用 @Async
和自定义线程池调用依赖项。
解决方法
事件循环不是你自己启动的,也不是你自己写的。在 webflux 中,事件循环由底层网络服务器 (netty) 创建,该服务器根据主机拥有的内核数量运行几个事件循环。
我无法在单个应用程序上同时运行 2 个不同的网络服务器实现。我不确定,Spring 团队的某个人需要在这里回答更具体的问题。
Tbh,如果这是一个大而重要的项目,我会保留原始服务器,然后通过在前面使用负载均衡器,首先复制请求并将它们发送到两个服务并实现端点,然后运行它并行运行一段时间以确认其运行良好,然后关闭并行运行。并同时为每个/几个端点执行此操作。
还有用于此目的的特定阴影工具,例如 goreplay
。
req ---------> LB ------> original
\
\------> webflux
req ---------> LB
\
\------> webflux
// Or for instance goreplay that runs on a host and also
// shadows requests forward to another service
req ---------> original
\
\------> webflux
永远不会有任何顺利的迁移方式。