Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Signalling server performance issue: Python vs NodeJS

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?

like image 1000
Xavier Araújo Avatar asked Jan 09 '19 15:01

Xavier Araújo


1 Answers

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.

like image 68
OrangeDog Avatar answered Oct 10 '22 06:10

OrangeDog