I'm developing a WebRTC application that requires a specific signalling server implementation. Initially I was developing the server in NodeJS but then I decided to migrate to Python (using Django Channels AsyncWebsocketConsumer to communicate with the clients through Websockets). After the migration I used the WebSocket benchmarking tool Thor to compare both implementations and these are the results obtained (5000 websocket connections, each one sending 1000 messages):
Python (Django Channels) Implementation:
class SignallingConsumer(AsyncWebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.peer = None
self.signal = None
self.is_peer_registered = False
async def connect(self):
await self.accept()
async def disconnect(self, close_code):
pass
async def receive(self, text_data=None, bytes_data=None):
pass
NodeJS implementation:
method.start = function () {
this.webServer = this.createWebServer();
this.webServer.listen(this.config.port, function (){
console.log("Web server is listening");
});
this.socket = this.createWebSocket(this.webServer);
this.socket.on('connection', function(ws) {
var pingsCompleted = 0;
ws.on('message', function(evt) {
}.bind(this));
// Set out ping/pong mechanism
var pingInterval = setInterval(function() {
if(pingsCompleted > 2) {
ws.close();
}
else {
ws.ping();
pingsCompleted++;
}
}.bind(this), config.pingPeriod);
ws.on('pong', function(evt) {
pingsCompleted = 0;
}.bind(this));
ws.on('close', function(evt) {
}.bind(this));
Python (Django Channels) Results:
Online 30792 milliseconds
Time taken 30792 milliseconds
Connected 3714
Disconnected 0
Failed 1286
Total transferred 4.43MB
Total received 525.91kB
Durations (ms):
min mean stddev median max
Handshaking 4795 11410 5517 10824 23923
Latency NaN NaN NaN NaN NaN
NodeJS Results:
Online 41307 milliseconds
Time taken 41307 milliseconds
Connected 4051
Disconnected 0
Failed 949
Total transferred 952.72kB
Total received 693.4kB
Durations (ms):
min mean stddev median max
Handshaking 2 1124 1044 860 5200
Latency NaN NaN NaN NaN NaN
So altough the number of failed connections is more or less the same in both implementations, the duration of the handshake negotiation in Django Channels is much slower than in NodeJS, which made me reconsider the migration for Python.
So are these results normal? Is it better to use NodeJS in a case like this?
NodeJS does its non-blocking I/O at a pretty low level and is backed by V8, which does pretty good JIT optimisations.
Django channels are a higher-level construct, and performance will also heavily depend on the Python implementation. CPython, among other things, interprets bytecode directly and uses a global execution lock.
I would expect NodeJS to perform better than Django on CPython. However, if you prefer Django for other reasons, you may want to compare performance on PyPy, IronPython and Jython.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With