I am looking into performance of .NET Core on a linux box. Specifically making sure what kind of limitations may be from tools available within the framework itself.
I've been hitting the box with ~ 50,000 pps. So far, it seems ~ 20,000 pps is what the UDPClient has been able to achieve before a fair bit of packets get dropped. Using another tool (syslog-ng) there's a rare/low packet loss rate.
If I'm looking to handle upwards of 50K pps, is UdpClient able to handle this with proper tuning?
using (UdpClient udpListener = new UdpClient(_sysLogPort))
{
udpListener.Client.ReceiveBufferSize = _bufferSize;
while (!_cts.IsCancellationRequested)
{
try
{
UdpReceiveResult result = await udpListener.ReceiveAsync();
}
catch (Exception ex)
{
}
}
}
Even if your app launches a new thread with udpListener.ReceiveAsync();
, it waits for its termination before trying to receive a new packet. So there is only one thread at a time that handles a new received UDP packet to create an object of type UdpReceiveResult. So, it is rather similar to a single-threaded app: you do not make use of the opportunity to run on a multi-core system.
You may get better rates (depending on your hardware, obviously), with the following way to write your program. In this example, there is a pool of 5 threads that run in parallel to create multiple instances of UdpReceiveResult at the same time. Even if packets are handled by the kernel one at a time, the userland process of creating instances of UdpReceiveResult is done in parallel, with this way of programming.
// example of multithreaded UdpClient with .NET core on Linux
// works on Linux OpenSuSE LEAP 42.1 with .NET Command Line Tools (1.0.4)
// passed tests with "time nping --udp -p 5555 --rate 2000000 -c 52000 -H localhost > /dev/null"
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace hwapp {
class Program {
// listen to port 5555
UdpClient udpListener = new UdpClient(5555);
static void Main(string[] args) {
Program p = new Program();
// launch 5 threads
Task t0 = p.listen("thread 0");
Task t1 = p.listen("thread 1");
Task t2 = p.listen("thread 2");
Task t3 = p.listen("thread 3");
Task t4 = p.listen("thread 4");
t0.Wait(); t1.Wait(); t2.Wait(); t3.Wait(); t4.Wait();
}
public async Task listen(String s) {
Console.WriteLine("running " + s);
using (udpListener) {
udpListener.Client.ReceiveBufferSize = 2000;
int n = 0;
while (n < 10000) {
n = n + 1;
try {
UdpReceiveResult result = udpListener.Receive();
} catch (Exception ex) {}
}
}
}
}
}