Социальные штуки в Django с Redis часть 1
Для одного из сайтов надо было писать начальные социальные штуки, типа количество пользователей онлайн и количество новых комментариев для постов. Т.к. реализация этого с sql базами достаточно затратно по ресурсам и не самое простое дело, то было выбрано nosql хранилище Redis. В нем легко хранить ключи и большое количество значений, которое легко можно получить для конкретных нужд.
Сначала рассмотрим реализацию индикатора пользователей онлайн вместе с Django.
Рассмотрим сначала теоретическую часть работы такого индикатора. Т.к. в вебе нет каких-либо четких механизмов узанавания, кто сейчас на сайте, то применяется простая практика. Каждую минуту записывается, кто из пользователей зашел на сайт, а раз в 5 минут делается выборка (группировка юзеров в каждую минуту) и вычисляется сколько их было. В моем конкретном примере, все пользователи зарегистрированы, т.е. учитывать анонимов не требуется. В Django для учета каждого пользователя и занесения его в базу очень подходит мидлварь (middleware). При заходе пользователя на любую страницу сайта, миддлварь его обрабатывает и заносит в базу со значением ключа указывающем время (например 23:10). А при запросе счетчиком, будут выбираться 5 ключей (23:10, 23:09, 23:08, 23:07, 23:06) объединяться и отдаваться. Общий процесс можно увидеть на картинке (не моей):
Рассмотрим код миддлвари:
class OnlineUsersMiddleware: def process_request(self, request): try: dbwork.set_to_key(request.user.id) except: pass
Как видно, вся работа миддлвари это получить id юзера и передать его в функцию работы с базой.
Рассмотрим саму функцию dbwork.set_to_key():
def current_key(): return datetime.now().strftime('%H:%M') def set_to_key(user_id): key = current_key() redis_db.sadd(key, user_id) redis_db.expire(key, 360)
Первая (current_key) – выдает нам просто время (ее можно и соввместить впринципе), вторая (set_to_key), получает ключ, добавляет в базу ключ set, в который добавляем пользовательский id и устанавливаем на него время жизни 6 минут.
Далее, рассмотри функцию, которая выводит количество пользователей онлайн:
def get_online(): now = datetime.now() interval = [now - timedelta(minutes=x) for x in range(5)] interval = [i.strftime('%H:%M') for i in interval] try: online = len(redis_db.sunion(interval)) except: online = 1 return int(online)
тут interval – это список наших ключей, который получается получением дельты с текущим временем и 5 минут назад, потом по нему с помощью sunion() получаем все id пользователей, а len – количество (т.к. мне не нужны были имена, а только количество).
Для получения и выведения этого значения был написан контекст процессор, т.к. значение требуется во всех шаблонах:
def users_online(request): users = get_online() return {'count_users_online': users}
Во всех модулях, redis_db это конект к базе редиса через официальный модуль Redis, примерно так открывающий коннект:
try: redis_db = redis.Redis(host=getattr(settings, 'REDIS_HOST', 'localhost'), \ port=getattr(settings, 'REDIS_PORT', 6379), \ db=getattr(settings, 'REDIS_DB', 0), \ password=getattr(settings, 'REDIS_PASS', ''), socket_timeout=0.01) except: pass
Все, после этого можно использовать. Как видно – делается легко и просто, к тому же не захламляет sql базу и не сказывается на производительности (nosql очень быстр). Вместо использования redis можно использовать тот же memcache.


