利用Redis统计在线用户数

原文来自:http://flask.pocoo.org/snippets/71/

功能需求:统计10分钟内在线用户数。

实现思路:利用Redis的Sets数据格式,以unix时间戳(秒)除以60的分钟数作为Redis的Key,value就是用户唯一标志(如id)的列表。当有新用户进来时,就将用户id加入当前这一分钟的队列里面去,并且将此key的超时设置为10分钟。

原文:

You can take the current time since 1970 in seconds, divide it by 60 and build a key based on that, then add a user to that set. Make the set expire after the maximum number of seconds you give a user in activity and when you want to query all active users you just build a union of the keys of the last N minutes.

主要代码:

from redis import Redis
redis = Redis()

import time
from datetime import datetime

ONLINE_LAST_MINUTES = 5

def mark_online(user_id):
    now = int(time.time())
    expires = now + (app.config['ONLINE_LAST_MINUTES'] * 60) + 10
    all_users_key = 'online-users/%d' % (now // 60)
    user_key = 'user-activity/%s' % user_id
    p = redis.pipeline()
    p.sadd(all_users_key, user_id)
    p.set(user_key, now)
    p.expireat(all_users_key, expires)
    p.expireat(user_key, expires)
    p.execute()

'''
根据用户最新活动时间,来判断该用户是否在线
'''
def get_user_last_activity(user_id):
    last_active = redis.get('user-activity/%s' % user_id)
    if last_active is None:
        return None
    return datetime.utcfromtimestamp(int(last_active))

'''
列出所有在线用户
'''
def get_online_users():
    current = int(time.time()) // 60
    minutes = xrange(app.config['ONLINE_LAST_MINUTES'])
    return redis.sunion(['online-users/%d' % (current - x)
                         for x in minutes])
'''
将用户(标志为request.remote_addr)标记为在线状态
'''
@app.before_request
def mark_current_user_online():
    mark_online(request.remote_addr)