Инструмент для расчета напряжений и соединений
Я создаю простой и быстрый инструмент стресс-тестирования для веб-приложения. Требования: наибольшее количество исходящих http-запросов (скажем, простых запросов) от одного узла.
Ранее мы использовали netty, и я выбрал его для написания этого простого теста. Это действительно просто, и я закончил только с 4 маленькими классами, расширяющими netty api ( код здесь), и он дает около 30K rps на машине localhost dev (linux).
Основным ограничением является лимит исходящих соединений (лимит открытого файла / сокета в linux), он составляет около 30-40 КБ на моей машине. Ты получаешь java.net.BindException
в этом случае. Таким образом, вы должны ограничить количество исходящих соединений Netty вручную, чтобы предотвратить снижение производительности при достижении предела.
Я реализую этот предел с помощью счетчика, и в первой версии я увеличил его в SimpleChannelUpstreamHandler.channelConnected
и уменьшается в future.getChannel().getCloseFuture().addListener
(см. код, комментарии в этих местах), и это не сработало: соединения не были увеличены, как предполагалось, и счетчик вышел из строя.
И только после того, как я положил приращение рядом bootstrap.connect
:
connected.incrementAndGet();
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
и уменьшение в SimpleChannelUpstreamHandler.messageReceived
:
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
// the same here - decrementing connections here is not fully fair but works!
connected.decrementAndGet();
e.getChannel().close();
}
Он начал работать. Единственная проблема - это немного несправедливо, потому что вы можете увеличить счетчик, но не можете подключиться или уменьшить и не смогли отключиться после него.
Итак, почему счетчик не работает в правильной версии?
ОБНОВЛЕНИЕ: попробовал как предложено, вкл / дек в SimpleChannelUpstreamHandler.channelConnected
:
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// by logic you should count connection here, but in practice - it doesn't work
connected.incrementAndGet();
ctx.getChannel().getCloseFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
connected.decrementAndGet();
}
});
e.getChannel().write(GET);
sent.incrementAndGet();
}
не работает, опять же непредсказуемые номера при отправке> подключены, например:
client1 stat: connected= 0, sent= 0, ERRORS: timeouts= 0, binds= 0, connects=0
client1 stat: connected= 11, sent= 4990, ERRORS: timeouts= 0, binds= 0, connects=0
client1 stat: connected= 1, sent= 8591, ERRORS: timeouts= 0, binds= 0, connects=0
client1 stat: connected= 459, sent=13064, ERRORS: timeouts= 0, binds= 5, connects=0
client1 stat: connected= 1545, sent= 7234, ERRORS: timeouts= 0, binds= 115, connects=0
client1 stat: connected= 0, sent=10037, ERRORS: timeouts= 0, binds= 80, connects=0
SADF
2 ответа
Вам не нужно увеличивать количество отправленных сообщений в ChannelFutureListener, который добавляется в ChannelFuture, который был возвращен из операции write(...). В противном случае вы увеличите его, даже если запись ожидает.
Теория.
В исходной версии вы уменьшаете счетчик подключений для всех попыток подключения, в случае неудачных. Если вы увеличите счетчик в channelConnected() и добавите понижающий прослушиватель в ChannelCloseFuture и этот момент, я думаю, вы получите лучший результат.
Это потому что
boostrap.connect().getChannel().getCloseFuture(...)
всегда будет вызывать operationComplete, даже если канал никогда не был подключен.
ОБНОВИТЬ:
Чтобы убедиться, что учитываются только подключенные каналы. В обратном вызове channelConnected() в STressClientHandler:
connected.incrementAndGet();
ctx.getChannel().getCloseFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
connected.decrementAndGet();
}
});