Josef Bauer Josef Bauer - 1 year ago 362
Java Question

Netty UDP Performance Issue

I've implemented three small UDP server. One with a plain Java DatagramSocket (threaded), one with Netty and the last one also with Netty but with a threaded message handling (because Netty doesn't support multiple threads with UDP).

After some measurements I got the following results for requests per second:

  • DatagramSocket ~30.000 requests/second

  • Netty ~1.500 requests/second

  • Netty (threaded): ~8.000 requests/second

The real application I have to implement must handle > 25.000 requests/second. So my question is if I make something wrong with Netty or if Netty is not designed to handle that much of connections per second?

Here are the implementations

DatagramSocket Main

public static void main(String... args) throws Exception {
final int port = Integer.parseInt(args[0]);
final int threads = Integer.parseInt(args[1]);
final int work = Integer.parseInt(args[2]);

DATAGRAM_SOCKET = new DatagramSocket(port);

for (int i = 0; i < threads; i++) {
new Thread(new Handler(work)).start();

DatagramSocket Handler

private static final class Handler implements Runnable {
private final int work;

public Handler(int work) throws SocketException { = work;

public void run() {
try {
while (!DATAGRAM_SOCKET.isClosed()) {
final DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
final InetAddress ip = receivePacket.getAddress();
final int port = receivePacket.getPort();
final byte[] sendData = "Hey there".getBytes();
final DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
} catch (Exception e) {
System.out.println("ERROR: " + e.getMessage());

Netty Main

public static void main(String[] args) throws Exception
final int port = Integer.parseInt(args[0]);
final int sleep = Integer.parseInt(args[1]);

final Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup());;
bootstrap.handler(new MyNettyUdpHandler(sleep));

Netty Handler (threaded)

public class MyNettyUdpHandler extends MessageToMessageDecoder<DatagramPacket> {
private final Random random = new Random(System.currentTimeMillis());
private final int sleep;

public MyNettyUdpHandler(int sleep) {
this.sleep = sleep;

protected void decode(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket, List list) throws Exception {
new Thread(() -> {
try {
} catch (InterruptedException e) {
System.out.println("ERROR while sleeping");

final ByteBuf buffer = Unpooled.buffer(64);
buffer.writeBytes("Hey there".getBytes()); DatagramPacket(buffer, datagramPacket.sender()));

The non threaded Netty Handler is the same but without the thread.

Answer Source

You can change your Netty decode() method like so to make it equivalent to the DatagramSocket code:

protected void decode(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket, List list) throws Exception {
  final Channel channel =;
  channel.eventLoop().schedule(() -> {
    final ByteBuf buffer = Unpooled.buffer(64);
    buffer.writeBytes("Hey there".getBytes());
    channel.writeAndFlush(new DatagramPacket(buffer, datagramPacket.sender()));
  }, random.nextInt(sleep), TimeUnit.MILLISECONDS);

But I'm guessing the sleep() code is simulating business code you will later execute. If that is the case make sure you don't run blocking code inside the handler.


To answer your question below: You got a bit confused with the channels. You create a pipeline in the bootstrap, and you bind to some port. The returned channel is the server channel. The channel in the handlers method (your decode method in your case), is like the socket you get when you accept() in traditional socket programming. Note that port you extracted from the incoming DatagramPacket - it's roughly the same. So you send data to the client back on this channel.

The code I wrote that schedules the response is simply doing the same as what your DatagramSocket code, and the threaded netty code you wrote. I wasn't sure why you did that, and simply assumed you have a business requirement to delay the response. If this isn't the case, you can remove the schedule call, and your code will run much faster. If your business logic is non-blocking, and runs in a few millis, you're done. If it's blocking, you need to try to find a non-blocking alternative, or run it in an executor, i.e. not on the event loop.

Hope this helps, even though this wasn't part of your original question. Netty is awesome, and I hate seeing bad examples and bad vibes about it so it's worth my time I guess ;)