Webclient 在 Docker 中泄漏内存?
Webclient Leaks Memory In Docker?
我正在尝试在我的项目中使用 Webclient,但是当我加载测试时,我注意到 docker 内存使用量在实例终止之前不会下降。
@Component
public class Controller {
//This is an endpoint to another simple api
//I use my local Ip instead of localhost in the container
private static final String ENDPOINT = "http://localhost:9090/";
private WebClient client;
public Controller(WebClient.Builder client) {
super();
this.client = client.build();
}
@Bean
public RouterFunction<ServerResponse> router() {
return RouterFunctions.route(GET("helloworld"), this::handle);
}
Mono<ServerResponse> handle(ServerRequest request) {
Mono<String> helloMono =
client.get().uri(ENDPOINT + "/hello").retrieve().bodyToMono(String.class);
Mono<String> worldMono =
client.get().uri(ENDPOINT + "/world").retrieve().bodyToMono(String.class);
return Mono.zip(helloMono, worldMono, (h, w) -> h + w)
.flatMap(s -> ServerResponse.ok().bodyValue(s));
}
}
这也是我的docker文件。
FROM openjdk:8
ENV SERVICE_NAME reactive-hello-world
ADD target/reactive-hello-world-*.jar $APP_HOME/reactive-hello-world.jar
RUN mkdir /opt/reactor-netty/
EXPOSE 9010
CMD java \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=localhost \
-Dcom.sun.management.jmxremote.port=9010 \
-Dcom.sun.management.jmxremote.rmi.port=9010 \
-Xmx190M \
-jar reactive-hello-world.jar
EXPOSE 8080
我是不是哪里漏了一步?
编辑:这是一些图片
负载测试前:
负载测试后
如您所见,GC 正常进行,但内存并未减少。如果我让测试继续,它会在几分钟内杀死实例。
我已经使用 RestTemplate
尝试了类似的代码,但我没有遇到任何问题,内存通常不会超过 400MB,即使我长时间 运行 Jmeter 也是如此。你能帮助理解发生了什么吗?
编辑:我也尝试过已弃用的 AsyncRestTemplate
,我也没有发现它有问题。
编辑:我已经为此示例创建了存储库。请检查您是否可以重现该问题。
The Webclient Hello World(JMX 在此存储库中)
我认为您的问题与 RestTemplate
和 WebClient
没有任何关系。您的 GC 图看起来很正常。看起来没有泄漏,因为每当 GC 发生时,分配的内存似乎能够回到以前的水平。
重要的是要注意,当发生垃圾回收时,您不会总是看到容器内存使用率下降。这是因为 Java 虚拟机在 GC 后不一定 return 内存返回系统。这意味着,即使一部分内存在您的进程中的 GC 之后 unused/freed,它仍可能从进程外部显示为“已使用”。
明确一点:在某些情况下,JVM 确实 return 将内存返回给系统,这取决于各种因素,包括所使用的垃圾收集器。
从你的例子的第二张截图的GC图表来看,GC图表看起来很正常,但似乎有相当少量的堆被释放回系统(橙色区域)。
您可以尝试通过 -XX:+UseG1GC
JVM 标志切换到 G1 GC,并调整行为以通过调整 -XX:MinHeapFreeRatio
和 -XX:MaxHeapFreeRatio
更积极地将未分配的内存释放回系统,特别是通过将 -XX:MaxHeapFreeRatio
值从默认的 70% 减少到一个较低的数字。参见 here。
Lowering -XX:MaxHeapFreeRatio to as low as 10% and -XX:MinHeapFreeRatio has shown to successfully reduce the heap size without too much performance degradation; however, results may vary greatly depending on your application. Try different values for these parameters until they're as low as possible, yet still retain acceptable performance.
有关该主题的更多信息,请参阅:
Does GC release back memory to OS?
没关系,小伙子们,我找到了答案,请参阅:
https://github.com/reactor/reactor-netty/issues/1304
本质上,reactor netty 依赖已经过时了。
我正在尝试在我的项目中使用 Webclient,但是当我加载测试时,我注意到 docker 内存使用量在实例终止之前不会下降。
@Component
public class Controller {
//This is an endpoint to another simple api
//I use my local Ip instead of localhost in the container
private static final String ENDPOINT = "http://localhost:9090/";
private WebClient client;
public Controller(WebClient.Builder client) {
super();
this.client = client.build();
}
@Bean
public RouterFunction<ServerResponse> router() {
return RouterFunctions.route(GET("helloworld"), this::handle);
}
Mono<ServerResponse> handle(ServerRequest request) {
Mono<String> helloMono =
client.get().uri(ENDPOINT + "/hello").retrieve().bodyToMono(String.class);
Mono<String> worldMono =
client.get().uri(ENDPOINT + "/world").retrieve().bodyToMono(String.class);
return Mono.zip(helloMono, worldMono, (h, w) -> h + w)
.flatMap(s -> ServerResponse.ok().bodyValue(s));
}
}
这也是我的docker文件。
FROM openjdk:8
ENV SERVICE_NAME reactive-hello-world
ADD target/reactive-hello-world-*.jar $APP_HOME/reactive-hello-world.jar
RUN mkdir /opt/reactor-netty/
EXPOSE 9010
CMD java \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=localhost \
-Dcom.sun.management.jmxremote.port=9010 \
-Dcom.sun.management.jmxremote.rmi.port=9010 \
-Xmx190M \
-jar reactive-hello-world.jar
EXPOSE 8080
我是不是哪里漏了一步?
编辑:这是一些图片
负载测试前:
负载测试后
如您所见,GC 正常进行,但内存并未减少。如果我让测试继续,它会在几分钟内杀死实例。
我已经使用 RestTemplate
尝试了类似的代码,但我没有遇到任何问题,内存通常不会超过 400MB,即使我长时间 运行 Jmeter 也是如此。你能帮助理解发生了什么吗?
编辑:我也尝试过已弃用的 AsyncRestTemplate
,我也没有发现它有问题。
编辑:我已经为此示例创建了存储库。请检查您是否可以重现该问题。
The Webclient Hello World(JMX 在此存储库中)
我认为您的问题与 RestTemplate
和 WebClient
没有任何关系。您的 GC 图看起来很正常。看起来没有泄漏,因为每当 GC 发生时,分配的内存似乎能够回到以前的水平。
重要的是要注意,当发生垃圾回收时,您不会总是看到容器内存使用率下降。这是因为 Java 虚拟机在 GC 后不一定 return 内存返回系统。这意味着,即使一部分内存在您的进程中的 GC 之后 unused/freed,它仍可能从进程外部显示为“已使用”。
明确一点:在某些情况下,JVM 确实 return 将内存返回给系统,这取决于各种因素,包括所使用的垃圾收集器。
从你的例子的第二张截图的GC图表来看,GC图表看起来很正常,但似乎有相当少量的堆被释放回系统(橙色区域)。
您可以尝试通过 -XX:+UseG1GC
JVM 标志切换到 G1 GC,并调整行为以通过调整 -XX:MinHeapFreeRatio
和 -XX:MaxHeapFreeRatio
更积极地将未分配的内存释放回系统,特别是通过将 -XX:MaxHeapFreeRatio
值从默认的 70% 减少到一个较低的数字。参见 here。
Lowering -XX:MaxHeapFreeRatio to as low as 10% and -XX:MinHeapFreeRatio has shown to successfully reduce the heap size without too much performance degradation; however, results may vary greatly depending on your application. Try different values for these parameters until they're as low as possible, yet still retain acceptable performance.
有关该主题的更多信息,请参阅:
Does GC release back memory to OS?
没关系,小伙子们,我找到了答案,请参阅:
https://github.com/reactor/reactor-netty/issues/1304
本质上,reactor netty 依赖已经过时了。