Недавно я запустил сайт backgrounddating.com, одной из возможностей которого является чат с другими пользователями в режиме реального времени. Документации (как на русском, так и на английском), позволяющей быстро вникнуть в написание подобных приложений с помощью технологии WebSocket пока что мало, поэтому я решил написать данное руководство. Итак, задача состоит в том, чтобы любой пользователь мог отправлять другим пользователям сообщения, и, если у получателя сообщения открыт чат с этим пользователям, то он сразу же видел входящие сообщения (а в ином случае он мог прочитать сообщения позже: то есть при открытии чата загружается история последних сообщений).
Если вам нужно, чтобы пользователи могли общаться не только вдвоём, а группами из любого количества человек, то сделать это можно почти что элементарно: описанная реализация, по сути, рассчитана на такое расширение функциональности.
Сразу уточню, что это не единственный способ реализовать подобное. Вы можете использовать другой асинхронный веб-сервер (например node.js), можете использовать другую очередь сообщений (или вообще её не использовать, если вам подходят особенности такого варианта: с пользователями одного канала обязательно общается один и тот же worker веб-сервера). Я даже не утверждаю, что этот вариант самый лучший (но в данном случае он подошёл лучше всех). В конце концов, мы здесь вообще не будем рассматривать костыли (long polling, Flash) для старых браузеров (а это почти все версии IE, например), не поддерживающих веб-сокеты, и даже не будем рассматривать возможность подключаться из тех браузеров, которые уже поддерживают протокол WebSocket, но не стандартизированную версию (RFC 6455), а одну из устаревших. О том, как можно включить поддержку устаревшей версии «draft 76» (она же «hixie-76»), смотрите в документации Tornado.
Тем не менее, что можно сказать точно — этот способ работает хорошо, причём не в одном проекте, а во многих (описанный способ реализации уже давно применяется, хоть о нём пока и не очень много информации). Например, сервер, на котором работает Background Dating — это на данный момент самый младший VPS от Linode (512 MiB памяти), но нагрузка на процессор не поднималась более 20—40 процентов, а использование оперативной памяти — около 30%. Причём ресурсы используют в основном gunicorn (веб-сервер, на котором работает Django) и PostgreSQL. Но тут нет абсолютно ничего удивительного, поскольку ни для кого не секрет, что Tornado достаточно лёгкий, чтобы не просто работать быстро, но даже справляться с C10k (о чём уже было на Хабрахабре).
Итак, мы будем использовать Django 1.4.2, Tornado 2.4, Redis 2.6.5 и PostgreSQL 9.2.1 (на самом деле вы можете использовать и другую реляционную СУБД — у Django есть много разных бэкэндов). Для подключения к Redis будет использоваться стандартный для Python клиент redis-py, а также brükva (асинхронный Redis-клиент для использования с Tornado). Для того, чтобы развернуть всё это на сервере, мы будем использовать haproxy и nginx, для запуска Django-проекта в production будем использовать веб-сервер gunicorn, а управлять запуском веб-серверов для Django и Tornado будет Supervisor.
Если вам нужно, чтобы пользователи могли общаться не только вдвоём, а группами из любого количества человек, то сделать это можно почти что элементарно: описанная реализация, по сути, рассчитана на такое расширение функциональности.
Сразу уточню, что это не единственный способ реализовать подобное. Вы можете использовать другой асинхронный веб-сервер (например node.js), можете использовать другую очередь сообщений (или вообще её не использовать, если вам подходят особенности такого варианта: с пользователями одного канала обязательно общается один и тот же worker веб-сервера). Я даже не утверждаю, что этот вариант самый лучший (но в данном случае он подошёл лучше всех). В конце концов, мы здесь вообще не будем рассматривать костыли (long polling, Flash) для старых браузеров (а это почти все версии IE, например), не поддерживающих веб-сокеты, и даже не будем рассматривать возможность подключаться из тех браузеров, которые уже поддерживают протокол WebSocket, но не стандартизированную версию (RFC 6455), а одну из устаревших. О том, как можно включить поддержку устаревшей версии «draft 76» (она же «hixie-76»), смотрите в документации Tornado.
Тем не менее, что можно сказать точно — этот способ работает хорошо, причём не в одном проекте, а во многих (описанный способ реализации уже давно применяется, хоть о нём пока и не очень много информации). Например, сервер, на котором работает Background Dating — это на данный момент самый младший VPS от Linode (512 MiB памяти), но нагрузка на процессор не поднималась более 20—40 процентов, а использование оперативной памяти — около 30%. Причём ресурсы используют в основном gunicorn (веб-сервер, на котором работает Django) и PostgreSQL. Но тут нет абсолютно ничего удивительного, поскольку ни для кого не секрет, что Tornado достаточно лёгкий, чтобы не просто работать быстро, но даже справляться с C10k (о чём уже было на Хабрахабре).
Итак, мы будем использовать Django 1.4.2, Tornado 2.4, Redis 2.6.5 и PostgreSQL 9.2.1 (на самом деле вы можете использовать и другую реляционную СУБД — у Django есть много разных бэкэндов). Для подключения к Redis будет использоваться стандартный для Python клиент redis-py, а также brükva (асинхронный Redis-клиент для использования с Tornado). Для того, чтобы развернуть всё это на сервере, мы будем использовать haproxy и nginx, для запуска Django-проекта в production будем использовать веб-сервер gunicorn, а управлять запуском веб-серверов для Django и Tornado будет Supervisor.