Назад | Перейти на главную страницу

Проблемы с производительностью с Apache + Django + socket.io (длинный опрос) + Proxy

Я пытаюсь создать веб-сайт с помощью django, apache и socket.io. Благодаря некоторым руководствам и другим вопросам, связанным с stackoverflow, мне удалось заставить все работать, за исключением серьезной задержки, которая возникает, когда я отправляю несколько сообщений socket.io за короткий промежуток времени.

Краткая настройка (подробные настройки внизу)

Я запускаю сервер node.js socket.io за прокси, настроенным в Apache. Сообщения, отправляемые от клиентов socket.io на сервер socket.io, также будут перенаправлены на django, где я хочу зарегистрировать обработчик событий. Например, я хочу запускать событие каждый раз, когда клиент присоединяется к определенной комнате, чтобы отправить некоторые начальные данные через socket.io.

Django также может отправлять запросы на сервер socket.io для запуска событий socket.io (например, emit), для отправки сообщений всем или некоторым клиентам socket.io.

Чтобы отправлять и получать сообщения socket.io, я использую длинный HTTP-опрос.

Проблема

Пересылка этого сообщения в django, похоже, немного замедляет связь socket.io. Например, я реализовал простой эхо-сервер, который работает так:

клиент ---send message-> прокси apache -> сервер socket.io ---http POST---> django -> обработчик событий (для отправки сообщения клиенту) ---http POST---> сервер socket.io -> прокси apache -> клиент

Это нормально работает, если я отправлю только одно сообщение. Но если я отправляю много сообщений за короткое время, возникает задержка, которая становится все больше и больше. Если я отправлю всего 10 сообщений подряд, общая задержка составит около 5 секунд, пока последнее эхо-сообщение не вернется к клиенту. Если я отправлю еще больше сообщений, я получу эффект, что всегда будет получаться 3-4 эхо-сообщения подряд. После этого есть пауза около 2 секунд до прибытия следующего значка.

Этого не произойдет, если я не пересылаю сообщения в django, а отправляю эхо обратно прямо внутри сервера socket.io.

Конечно, следует ожидать, что этот дополнительный компонент немного замедлит работу, но это отставание кажется довольно серьезным.

Вопрос

Так что я сделал не так? Может быть, мой подход к пересылке сообщений в django по своей сути неправильный? Или есть какие-то конфигурации, которые я могу настроить, чтобы ускорить процесс? И откуда вообще такое отставание?

Подробная настройка (с фрагментами кода)

Apache 2.4.7

виртуальный хост:

<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.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);
    });
});

Джанго

переслать сообщение на 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)

представление для обработки сообщений socket.io:

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)

зарегистрируйте обработчик событий сообщения:

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

Клиент

io.js

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

Следующий рисунок также должен проиллюстрировать, как я предполагал, что отдельные компоненты будут взаимодействовать друг с другом.