Анализ дампа кучи показал, что память выделяется одним экземпляром io.netty.util.concurrent.DefaultEventExecutor , который использует LinkedBlockingQueue с внутренним неограниченным размером.Эта очередь растет бесконечно под нагрузкой, вызывая проблему.
DefaultEventExecutor создается Camel из-за параметра usingExecutorService , который по умолчанию имеет значение true (возможно, не является хорошим выбором).Установка usingExecutorService = false заставляет Netty использовать свой цикл обработки событий вместо исполнителя, который работает намного лучше.
Теперь я получаю 600.000 сообщений в секунду с пропускной способностью с данными, используя линию Windowsперерывы (CR NL) с устойчивым использованием оперативной памяти около 200 МБ (-Xmx500M).Хорошо.
Хотя с данными, использующими разрывы строк Unix (NL), пропускная способность составляет всего около 6,500 сообщений в секунду, на два порядка медленнее, что все еще вызывает недоумение.
Причина в том, что Camel создает свой собственный org.apache.camel.component.netty4.codec.DelimiterBasedFrameDecoder класс путем подкласса Netty io.netty.handler.codec.DelimiterBasedFrameDecoder - Я не знаю почему, так как класс Кэмел не добавляет никакой функциональности.Но путем создания подклассов Camel предотвращает определенную оптимизацию внутри DelimiterBasedFrameDecoder , который переключается на io.netty.handler.codec.LineBasedFrameDecoder внутренне, но только если не является подклассом.
Чтобы преодолеть это, мне нужно было явно объявить декодер и кодеры, используя вместо этого классы Netty, в дополнение к настройке usingExecutorService = false.
Теперь я получаю пропускную способность 600 000 сообщений в секунду с данными, также используя разрывы строк Unix (NL) иувидеть устойчивое использование оперативной памяти около 200 МБ.Это выглядит намного лучше.
public abstract class MyRouteBuilderTestBase extends CamelTestSupport {
private final int nettyPort = AvailablePortFinder.getNextAvailable();
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
@Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry registry = super.createRegistry();
List<ChannelHandler> decoders = new ArrayList<>();
DefaultChannelHandlerFactory decoderTextLine = new DefaultChannelHandlerFactory() {
@Override
public ChannelHandler newChannelHandler() {
return new io.netty.handler.codec.DelimiterBasedFrameDecoder(1024, true, Delimiters.lineDelimiter());
// Works too:
// return new LineBasedFrameDecoder(1024, true, true);
}
};
decoders.add(decoderTextLine);
ShareableChannelHandlerFactory decoderStr = new ShareableChannelHandlerFactory(new StringDecoder(CharsetUtil.US_ASCII));
decoders.add(decoderStr);
registry.bind("decoders", decoders);
List<ChannelHandler> encoders = new ArrayList<>();
ShareableChannelHandlerFactory encoderStr = new ShareableChannelHandlerFactory(new StringEncoder(CharsetUtil.US_ASCII));
encoders.add(encoderStr);
registry.bind("encoders", encoders);
return registry;
}
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
from("netty4:tcp://localhost:" + nettyPort + "?clientMode=true&textline=true&sync=false&usingExecutorService=false&encoders=#encoders&decoders=#decoders")
.to("log:throughput?level=INFO&groupInterval=10000&groupActiveOnly=false");
}
};
}
protected void startServerStub(String testdata) throws Exception {
serverSocket = new ServerSocket(nettyPort);
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
for (;;) {
out.print(testdata);
}
}
@After
public void after() throws Exception {
if (out != null) out.close();
if (clientSocket != null) clientSocket.close();
if (serverSocket != null) serverSocket.close();
}
}
Обновление : проблема использования памяти не в утечке памяти (и я сожалею, что сформулировал свой вопрос таким образом), а в буферизации.Пожалуйста, ознакомьтесь с комментариями к этому ответу пользователей Bedla и Claus Ibsen, чтобы получить хорошее представление о последствиях решения, изложенного выше.Пожалуйста, обратитесь к CAMEL-13527