【发布时间】:2017-02-24 13:25:45
【问题描述】:
我在下面的代码中做错了吗?或者 netty4 组件是否存在一些已知问题,它只是内存使用率很高?
我的问题:
我正在使用 Camel 的 netty4 组件从套接字流式传输数据,聚合它,然后将其发送出去。
我尝试了许多不同的策略来聚合数据,但似乎没有任何帮助或损害内存使用。
我的聚合周期为 30 秒,在这 30 秒内传入的数据总计约为 1.3MB。
但是,我注意到我的内存使用量每 30 秒增加 4MB。我在 Linux 中使用watch free -m 来监控内存消耗。除了运行 Camel 进程的终端外,没有其他进程在前台运行。在运行 Camel 进程之前,内存使用是完全稳定的(MB 规模没有波动)。
我已经使用了 Camel 文档提供的几乎所有 netty4 设置,这对我来说是显而易见的,似乎没有什么能减少正在使用的内存量。
我使用命令行从命令行运行 Camel 实例
java -Xms200M -Xmx275M -Xss512k -Drolling_log_dir=/logs/ -jar myCamel.jar
我的路线:
from( netty4:tcp://localhost:12345?clientMode=true&textline=true ).routeId( routeId + "A" )
.log( LoggingLevel.INFO, rollingLogFile, "${body}" )
.aggregate( constant(true), new StringAggregationStrategy(dataType) )
.completionInterval( 30000 )
.to( fileUri );
from( fileUri ).routeId( routeId + "B" )
.process(doTheThing)
.to( pushFile )
.log( "Transferred ${file:name} complete" );
StringAggregationStrategy.java:
package com.aggregators;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;
public class StringAggregationStrategy implements AggregationStrategy {
private static Path tempFileDir;
public StringAggregationStrategy(String dataType){
tempFileDir = Paths.get("camelTempAggFileStorage/" + dataType + "/");
}
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
String newBody = newExchange.getIn().getBody(String.class);
String exchangeId;
Path tempAggFilePath;
if (!Files.exists(tempFileDir)){
try {
Files.createDirectories(tempFileDir);
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (oldExchange == null){
cleanDirectory(tempFileDir);
exchangeId = newExchange.getExchangeId();
tempAggFilePath = Paths.get(tempFileDir.toString() + "/" + exchangeId + ".txt");
} else{
File oldFile = oldExchange.getIn().getBody(File.class);
tempAggFilePath = oldFile.toPath();
}
try (BufferedWriter writer = Files.newBufferedWriter(tempAggFilePath, StandardOpenOption.APPEND, StandardOpenOption.CREATE)){
if (oldExchange == null) {
writer.write(newBody);
newExchange.getIn().setBody(tempAggFilePath.toFile());
return newExchange;
} else {
writer.newLine();
writer.write(newBody);
oldExchange.getIn().setBody(tempAggFilePath.toFile());
return oldExchange;
}
} catch (IOException e) {
e.printStackTrace();
}
return oldExchange;
}
private void cleanDirectory(Path tempFileDir) {
for (File tempFile: tempFileDir.toFile().listFiles()){
if (!tempFile.isDirectory()){
tempFile.delete();
}
}
}
}
编辑: 使用 VisualVM 并监视应用程序的运行情况,似乎 Netty 在发生诸如 Broken Pipe 异常之类的事情时开始产生额外的线程,但这些线程从未被清理干净。在 Java 程序运行 17 小时后查看堆转储时,我发现最大的违规者(类的实例数)是 io.netty.util.Recycler$DefaultHandle 和 io.netty.channel.ChannelOutboundBuffer$Entry,分别为 20.2% (59,630) 和 19.8% (58,306) ) 我堆中的类。
关于 Camel 如何缓解这些设置的任何想法?
【问题讨论】:
-
"我的内存使用量每 30 秒增加 4MB。" -- 怎么衡量的?
-
啊抱歉,我解释了其他所有内容,但...哈哈。除了带有 Java 进程的终端之外,我已经关闭了所有东西,我正在查看 Linux 中的
free -m命令。在我运行该进程之前,内存处于稳定状态,所以我不知道其他任何东西都在同时耗尽内存。我应该更新问题 -
磁盘上的 1.3MB 由于压缩等原因,在加载到内存时可能会导致 4MB。因此,每 30 秒,您会将传入的数据聚合到一个文件中,然后将其保存在内存中。内存增加的原因可能是处理完成时文件没有从内存中删除,或者 GC 只是在需要时才启动。如果您只是将传入的数据附加到您的交换主体而不是创建一个文件,会发生什么?
-
@noMad17 我们之前已将传入数据附加到交易所的正文中,但结果仍然相同。我什至通过
System.gc()进入代码,看看我是否可以让垃圾收集器跳进去。它似乎对正在使用的内存没有影响。 -
好的,
.to( pushFile )中发生了什么?它实际上是对文件组件的调用,还是您在其中做了一些可能导致文件保存在内存中的事情?
标签: java apache-camel netty