开发:uwsgi开多进程引发的LocMemCache的session冲突

2023.11.18

今天上线了新功能,其中一个具体的实现逻辑如下:

使用 request.session 存储 API 的响应数据,确保会话会偶尔正确地保存并在需要时能够正确地读取数据。

predict.py -- 通过sessions存储all_response_data再重定向对predicted_results页面传递api返回的值


if response_status_code == 200:
    all_response_data = []

    # ____response____
    response_shape_data = response_shape.json()
    response_aerobic_data = response_aerobic.json()
    response_gram_data = response_gram.json()
    all_response_data.append(response_shape_data)
    all_response_data.append(response_aerobic_data)
    all_response_data.append(response_gram_data)
    #print(f'all_response_data: {all_response_data}')
    import logging

    logger = logging.getLogger('django')
    # ______________
    logger.error(f'log_all_response_data: {all_response_data}')
    if response_shape_data is None:
        return HttpResponse('ERROR')

    request.session['predicted_results'] = all_response_data
    logger.error(f'log_session: {json.dumps(dict(request.session))}')
    print('##############')
    return redirect(f'predicted_results/')

predicted_results.py -- 这是重定向走的一个view,这里通过request.session.get('predicted_results')获取上面存储在session里的值,然后返回在前端页面。

from django.shortcuts import render


def predicted_results(request):
    # print("json_data: ", json_data)                                                                                                                   
    results = request.session.get('predicted_results')
    import logging
    logger = logging.getLogger('django')
    logger.error(f'predicted_result_session: {results}')
    return render(request, "result/predicted_results.html", {"predicted_results": results})

这里遇到了一个诡异的问题,通过python manages.py runserver 0.0.0.0:8000 访问该功能,提交文件处理后重定向的predicted_results正常。

但是,通过 uwsgi --ini uwsgi.ini 启动的应用,再访问该功能的时候,会出现有时可以有时不可以的随机事件。

排查发现前端返回的无结果即失败时,log日志为:

log_all_response_data: [{'result_shape': [{'Name': 'GCF_001546385.1_ASM154638v1', 'preds': 'coccus'}, {'Name': 'GCF_002243035.1_ASM224303v1', 
'preds': 'coccus'}, {'Name': 'GCF_002243035.1_ASM224303v1-tst', 'preds': 'coccus'}]}, {'result_aerobic': [{'Name': 'GCF_001546385.1_ASM154638v
1', 'preds': 'anaerobe'}, {'Name': 'GCF_002243035.1_ASM224303v1', 'preds': 'anaerobe'}, {'Name': 'GCF_002243035.1_ASM224303v1-tst', 'preds': '
anaerobe'}]}, {'result_gram': [{'Name': 'GCF_001546385.1_ASM154638v1', 'preds': 'positive'}, {'Name': 'GCF_002243035.1_ASM224303v1', 'preds': 
'positive'}, {'Name': 'GCF_002243035.1_ASM224303v1-tst', 'preds': 'positive'}]}]                                                              
log_session: {"predicted_results": [{"result_shape": [{"Name": "GCF_001546385.1_ASM154638v1", "preds": "coccus"}, {"Name": "GCF_002243035.1_AS
M224303v1", "preds": "coccus"}, {"Name": "GCF_002243035.1_ASM224303v1-tst", "preds": "coccus"}]}, {"result_aerobic": [{"Name": "GCF_001546385.
1_ASM154638v1", "preds": "anaerobe"}, {"Name": "GCF_002243035.1_ASM224303v1", "preds": "anaerobe"}, {"Name": "GCF_002243035.1_ASM224303v1-tst"
, "preds": "anaerobe"}]}, {"result_gram": [{"Name": "GCF_001546385.1_ASM154638v1", "preds": "positive"}, {"Name": "GCF_002243035.1_ASM224303v1
", "preds": "positive"}, {"Name": "GCF_002243035.1_ASM224303v1-tst", "preds": "positive"}]}]}                                                 
predicted_result_session: None

注意这里的predicted_result_session: None,参照predicted_results.py的代码是在这里打印的。而这predicted_results.py的作用是取得session,但是这里session为空,很诡异。

为了进一步确定是这里session为空,在浏览器进行查看upload_ml_matrix/和predicted_results/的Cookie情况

predicted_results/的请求Cookie中的sessionid正确与upload_ml_matrix/一致,但是响应Cookie的sessionid值为空,定位到这里就是问题的关键。

那什么情况会造成这样的随机事件?多进程执行时会导致这种情况,这恰与uwsgi的配置有关:

(我的uwsgi.ini配置)

[uwsgi]
socket          = 127.0.0.1:8000
# http = 0.0.0.0:8000
chdir           = /home/aq/bacapp
wsgi-file       = bacapp/wsgi.py
master          = true
processes       = 2
threads         = 4
vacuum          = true

可以看到processes大于一个进程,这就属于多进程处理了,所以这是造成此bug的真凶。

如何解决?

LocalCache即本地的sessions是会话改变它也跟着变,所以我这里选择考虑使用像 RedisMemcached 这样的共享缓存解决方案来替换 LocMemCache。这些服务可以在会话改变的情况下session不变。

我选择Redis,使用docker进行部署

docker pull redis

docker run -p 6666:6379 --name bac_redis -itd redis:latest

pip install django-redis -i https://mirrors.aliyun.com/pypi/simple/

# 服务器开启6666端口,然后进行settings.py配置django,下面是我的配置
CACHES = { 
    'default': {
#        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'BACKEND': 'django_redis.cache.RedisCache',                                                                                           
        'LOCATION': 'redis://111.231.32.238:6666/1',
        'OPTIONS': {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }   
}



在 Django 配置中的 "LOCATION": 'redis://111.231.32.238:6666/1' 用于指定 Redis 服务器的连接信息。这个字符串是一个 URI 格式的地址,它的各部分含义如下:

redis://: 这是一个 URI 方案,指出使用的是 Redis。

111.231.32.238:6666: 这里指定了 Redis 服务器的地址和端口号。111.231.32.238 是本地主机的地址,6379 是 Redis 默认使用的端口号。如果您的 Redis 服务器配置在不同的地址或端口上,需要相应地修改这部分。

/1: 这部分指定了使用的 Redis 数据库。Redis 支持多个数据库(通常是从 0 到 15),您可以通过这个数字选择一个。在这个例子中,选择的是数据库 1。

优雅启动!

posted @   仗剑天涯横刀笑  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示