巨大的Django Session表,正常行为还是bug?

时间:2010-12-14 22:04:59

标签: django django-sessions

也许这是完全正常的行为,但我觉得django_session表比它应该的大得多。

首先,我每天运行以下清理命令,因此过期的会话导致 的大小:

DELETE FROM %s WHERE expire_date < NOW()

数字:

  • 我们每天都有大约5000名独立访客(机器人除外)。
  • SESSION_COOKIE_AGE设置为默认值,为期2周
  • 该表略高于 1,000,000行

所以,我猜测Django还会为访问该网站的所有机器人生成会话密钥,并且机器人不会存储cookie,因此它会不断生成新的cookie。

但......这是正常行为吗?是否有一个设置,以便Django不会为匿名用户生成会话,或者至少......没有会话的用户没有使用会话?

4 个答案:

答案 0 :(得分:17)

经过一些调试后,我设法找出了问题的原因。 我的一个中间件(以及我的大部分观点)中都有request.user.is_authenticated()

django.contrib.auth中间件将request.user设置为LazyUser()

来源:http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/middleware.py?rev=14919#L13(我不明白为什么会有return None,但确定......)

class AuthenticationMiddleware(object):
    def process_request(self, request):
        assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
        request.__class__.user = LazyUser()
        return None

LazyUser调用get_user(request)来获取用户:

来源:http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/middleware.py?rev=14919#L5

class LazyUser(object):
    def __get__(self, request, obj_type=None):
        if not hasattr(request, '_cached_user'):
            from django.contrib.auth import get_user
            request._cached_user = get_user(request)
       return request._cached_user

get_user(request)方法执行user_id = request.session[SESSION_KEY]

来源:http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/init.py?rev=14919#L100

def get_user(request):
    from django.contrib.auth.models import AnonymousUser
    try:
        user_id = request.session[SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
        backend = load_backend(backend_path)
        user = backend.get_user(user_id) or AnonymousUser()
    except KeyError:
        user = AnonymousUser()
    return user

在访问会话时将accessed设置为true:

来源:http://code.djangoproject.com/browser/django/trunk/django/contrib/sessions/backends/base.py?rev=14919#L183

def _get_session(self, no_load=False):
    """
    Lazily loads session from storage (unless "no_load" is True, when only
    an empty dict is stored) and stores it in the current instance.
    """
    self.accessed = True
    try:
        return self._session_cache
    except AttributeError:
        if self._session_key is None or no_load:
            self._session_cache = {}
        else:
            self._session_cache = self.load()
    return self._session_cache

这导致会话初始化。该错误是由错误的会话后端引起的,当accessed设置为true时,该会话后端也会生成会话...

答案 1 :(得分:3)

机器人是否可以访问您在用户会话中设置任何内容的任何页面(即使对于匿名用户),或者您使用session.set_test_cookie()的任何页面(例如,调用此方法时Django的默认登录视图) ?在这两种情况下,都会创建一个新的会话对象。在robots.txt中排除此类网址应该会有所帮助。

答案 2 :(得分:0)

对于我的情况,我错误地在SESSION_SAVE_EVERY_REQUEST = True中设置了settings.py而没有理解其确切含义。

然后,对我的django服务的每个请求都会生成一个会话条目,尤其是来自上游负载均衡器的心跳测试请求。几天后#39;跑步,django_session桌子变成了一张巨大的桌子。

答案 3 :(得分:-3)

Django提供management command to cleanup这些过期的会话!