1

I have a UDP server that receives packets at 40 pkts per seconds. The main loop is below:

 public void serve() {
        while(true) {
              ByteBuffer bytes = ByteBuffer.allocate(1024);
              bytes.clear();
              channel.receive(bytes);
              THandler th = new THandler(bytes);
              th.start();
        }
    }

Channel Initialization:

private final DatagramChannel channel ;  
channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(port));

The class THandler extends a thread class and it filters the message against a regular expression and then finds an id from the matching message. This id is then compared to a list of subscribers (approx 300k). followed by a db select followed by an update.

public void run() {

    if (!this.isValidLog()){ //does a regular expression match
        return;
    }
    String subsId = this.getSubscriberId(); // extracts the id from message
    if (this.isServiceSubscribed(subsId)) { // compares in a list of subscribers

        usageDetails = this.getServiceUsage(subsId); // db Query
        if(usageDetails.isFeatureAvailable()){
            usageDetails.updateUsageCounter(); // db Update
        }
    }


}

I have tried using ExecutorService also. But the problem is that I run out of CPU time with 99.6% or more in user.

Any inputs on how to improve the performance of the server and code are most welcome.

friedFingers
  • 245
  • 6
  • 18
  • It doesn't look like a matter of performance, while(true) { is a busy loop that will indeed eat up 100% of a cpu if there is nothing in there that will put the logic to rest for a period of time. As a test, try adding a Thread.sleep(1) in that busy loop to see how that influences the CPU usage. – Gimby Feb 01 '16 at 11:35
  • Please show the code that you use to prepare the `channel`. – Steve C Feb 01 '16 at 11:39
  • 1
    It seems like you need to profile your code. This can be done with `jvisualvm` that comes with your JDK. @EJP has a great answer otherwise – Steve C Feb 01 '16 at 12:02
  • 1
    I suggest you use a cached Thread Pool i.e. ExecutorService instead of creating a Thread for each packet. Creating a Thread is very expensive, and you might find the pool is rarely more than one thread in it. – Peter Lawrey Feb 01 '16 at 13:50
  • You only need to clear a ByteBuffer if you are re-using it. A new ByteBuffer is always `clear()` – Peter Lawrey Feb 01 '16 at 13:51

2 Answers2

2
  • Make sure the channel is in blocking mode.
  • You don't need to clear a newly created ByteBuffer.
  • Use an ExecutorService with a reasonably sized thread pool, instead of creating a new thread per datagram.
  • Ensure you are using O(1) data structures.
  • Combine the database lookup and update into one operation, using UPDATE ... WHERE, and get the update count if you need to see whether anything happened.
  • Ignore any suggestion to add sleeps into networking code. They are literally a waste of time.
user207421
  • 305,947
  • 44
  • 307
  • 483
0

Most likely your search is simply iteration through an array. You might want to replace these with a more efficient method.

Have a look at the Map specially HashMap and TreeMap

Dawnkeeper
  • 2,844
  • 1
  • 25
  • 41
  • I tried by pruning the list to only one subscriber, but to no avail, CPU still 100% occupied. – friedFingers Feb 01 '16 at 11:39
  • In that case the DatagramChannel might not be in blocking mode as @EJP mentioned is his answer. My suspicion was that the data handling/searching took up all the CPU. – Dawnkeeper Feb 01 '16 at 12:11