3

I'm trying to set up a website with django, apache and socket.io. Thanks to some tutorials and other stackoverflow questions, I managed to make everything work, except for a severe lag, that occurs when I send multiple socket.io messages within a short time span.

Short Setup (detailed setup at the bottom)

I'm running a node.js socket.io server behind a proxy configured in Apache. Messages send from socket.io clients to the socket.io server, will also forwarded to django, where I want to register event handler. For instance, I want to trigger an event, everytime a client joins a certain room, to send some initial data over socket.io.

Django can also send requests to the socket.io server, to trigger socket.io events (like emit), to send messages to all or certain socket.io clients.

To send and receive socket.io messages, I use http long polling.

Problem

This message forwarding to django, seem to slow down the socket.io communication quite a bit. For instance, I implemented a simple echo sever that works like this:

client ---send message--> apache proxy --> socket.io server ---http POST---> django --> event handler (to send message back to client) ---http POST---> socket.io server --> apache proxy --> client

This workes fine, if I only send one message. But if I send a lot of messages, within a short time, there is a lag that gets larger and larger. If I send just 10 messages in a row, there will be a total lag of about 5 seconds until the last echo message comes back to the client. If I send even more messages, I get the effect that always 3-4 echo messages will be received in a row. After that there is a pause of about 2 seconds until the next badge arrives.

This does not happen, if I don't forward messages to django, but send the echo back directly inside the socket.io server.

Of course it is to expect, that this additional component will slow down things a little, but this lag seems to be quite severe.

Question

So what did I do wrong? Is maybe my approach to forward messages to django inherently wrong? Or are there some configurations, that I can tweak to speed things up? And where does this lag come from in the first place?

Detailed Setup (with code excerpts)

Apache 2.4.7

  • www.example.com:80
  • Serves static files and django application
  • Is proxy for node.js socket.io server

virtual host:

<VirtualHost *:80>
        ServerName www.example.com
        ProxyRequests off
        ProxyPass        /socket.io http://localhost:8080/socket.io retry=0
        ProxyPassReverse /socket.io http://localhost:8080/socket.io
        WSGIDaemonProcess www.example.com processes=1 threads=1 display-name=%{GROUP}
        WSGIProcessGroup www.example.com
        WSGIScriptAlias / /path/to/wsgi.py
        DocumentRoot /var/www/example.com/
</VirtualHost>

Node.js server

  • runs on 127.0.0.1:8080
  • express application
  • forwards incoming messages to django (for event handling)
  • accepts post requests from django (to trigger socket.io events like emit/broadcast)

server.js

app = express();
server = http.Server(app);
io = require("socket.io")(server);
server.listen(8080);

app.use(express.bodyParser());

// incoming emit from django will emit a message over socket.io
app.post("/emit/", function (req, res) {
    var body = req.body,
        message = body.message;

    io.emit("message", message);
    res.send("everything is ok");
});

// forwarding incoming socket.io message to django
function forward(type, data, sessionId) {
    var options, req;

    data.sessionid = sessionId;
    data = JSON.stringify(data);
    console.log(data);
    options = {
        rejectUnauthorized: false,
        host: "www.example.com",
        port: 80,
        path: "/socket/" + type + "/",
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "Content-Length": data.length
        }
    };

    req = http.request(options, function(res){
        res.setEncoding("utf8");
    });

    req.write(data);
    req.end();
}


io.sockets.on("connection", function (socket) {

    var sessionId = socket.id;

    forward("connect", {}, sessionId);

    socket.on("disconnect", function () {
        forward("disconnect", {}, sessionId);
    });

    socket.on("message", function(message) {
        forward("message", { message: message }, sessionId);
    });

    socket.on("join", function (room) {
        socket.join(room);
        forward("join", { room: room }, sessionId);
    });

    socket.on("leave", function (room) {
        socket.leave(room);
        forward("leave", { room: room }, sessionId);
    });
});

Django

  • accepts incoming messages from socket.io server (http POST)
  • triggers event handler if registered
  • triggers socket.io events (i.e. emit/broadcast) by sending http POST requests to socket.io server (127.0.0.1:8080 without proxy)

forward message to socket.io

def emit(message):
    payload = {"message": message}
    headers = {"content-type": "application/json"}
    requests.post("http://127.0.0.1:8080/emit/", data=json.dumps(payload, cls=DjangoJSONEncoder), headers=headers, verify=False)

view to handle socket.io messages:

class MessageView(View):
    def post(self, request, *args, **kwargs):
        data = json.loads(request.body)
        try:
            sessionid = data["sessionid"]
            message = data["message"]
            //fire function will trigger event handler
            fire("message", sessionid, {"message": message})
            return HttpResponse("Everything worked :)")

        except Exception, e:
            return HttpResponseServerError(str(e))

    @csrf_exempt
    def dispatch(self, *args, **kwargs):
        return super(MessageView, self).dispatch(*args, **kwargs)

register a message event handler:

@on_message
def message_received(sessionid, data):
    //emit to all socket.io clients
    emit("someone has sent a message")

Client

  • connects to socket.io via www.example.com:80/socket.io

io.js

socket = io.connect(
    "http://www.example.com:80", 
    {
        "multiplex": false,   
        "transports": ["polling", "xhr-polling", "jsonp-polling"]
    }
);

Following graphic should also illustrate how I intended the single components to communicate with each other.

Current Setup

basilikum
  • 217
  • 3
  • 11
  • Have you managed to solve this issue? I need something similar and would like to know if there are any performance issues. Many thanks! – remus Dec 29 '16 at 12:36

0 Answers0