【问题标题】:Django channels with redis setup on heroku leaking memory在heroku上使用redis设置的Django频道泄漏内存
【发布时间】:2018-01-18 12:06:09
【问题描述】:

我在这里遵循了有些过时的指南: https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django

并成功设置带有频道的 django 应用:

> cat requirements.txt 
..
Django==1.10.6
asgi-redis==1.4.3
asgiref==1.1.2
channels==1.1.8
django-redis-cache==1.7.1
daphne==1.4.2
..

> cat Procfile 
web: daphne Landia.asgi:channel_layer --port $PORT --bind 0.0.0.0
worker: python manage.py runworker

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",
        "CONFIG": {
            "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')],
        },
        "ROUTING": "Landia.routing.channel_routing",
    },
}

问题在于,redis 内存消耗从 2M 开始,然后在 48 小时左右逐渐,非常缓慢地增长到 50MB,当配置空间耗尽并且我的服务器基本上开始抛出 5XX。

可以通过flush redis修复。

我假设通道/redis 没有丢弃它发出的回复。

任何想法如何解决,或至少调试这个问题?

我也用redis做session存储,我觉得是泄露的源头:

> heroku redis:cli
> info
...
# Keyspace
db0:keys=119,expires=119,avg_ttl=49389233
db1:keys=7749,expires=7749,avg_ttl=1192828136
> select 1
> keys *
...
7757) :1:django.contrib.sessions.cachechnb5cafa749ec3b1b8b6fc20903750f
7758) :1:django.contrib.sessions.cachechn975ee5d806f3b27d6492e3fad8218
7759) :1:django.contrib.sessions.cachechn659906572f30ed388e655b75fbf87

这是 django 频道会话设置:

CHANNEL_SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.RedisCache',
        'LOCATION': os.environ.get('REDIS_URL', 'redis://localhost:6379')
    },
}

以及在consumers.py中的用法

@allowed_hosts_only
@channel_session_user_from_http
def ws_connect(message):
    ...


@channel_session_user
def ws_receive(message):
   ...


@channel_session_user
def ws_disconnect(message):
    ...

有没有办法在断开连接时清除存储在 redis 中的会话信息,或者至少为 redis 键设置合理的 TTL?

【问题讨论】:

    标签: python django heroku memory-leaks django-channels


    【解决方案1】:

    我最近遇到了同样的问题,我的调查使我写在django-users group 上(简短的回答是 django-channels 不管理会话删除,只是等待它过期)。

    我自己想出来的,因为一旦 WebSocket 客户端断开连接,会话就没有用了:

    from channels.sessions import session_for_reply_channel
    
    @channel_session_user
    def ws_disconnect(message):
        ...
        session = session_for_reply_channel(message.reply_channel.name)
        session.delete(session.session_key)
    

    希望这对你有用。

    【讨论】:

      猜你喜欢
      • 2016-09-25
      • 1970-01-01
      • 2012-11-02
      • 2012-03-07
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 2012-01-06
      • 1970-01-01
      相关资源
      最近更新 更多