Nginx+Gunicorn(开启多worker)运行Django/Flask应用程序时关于共享内存(全局变量)的注意事项

29 篇文章 3 订阅

关于单例模式:

问题:单例模式在本地测试时一切正常,当运行在生产环境下,单例不生效,会创建出多个实例。

原因:Django/Flask本地环境的runserver为单进程多线程,单进程下当然共享一份内存,而在生产环境的多worker下,每个进程都有自己的内存空间,因此也有自己的实例。

 

关于全局变量:

同样的问题,在生产环境中,多个worker之间是无法共享一个全局变量的,一个worker修改了这个变量,其他worker是看不到改变后的结果的。

如果需要共享数据,应该使用数据库或者单独的缓存服务器。

 

补充:

  • 使用execute_from_command_line(django自带runserver)方式启动django应用时, 会先加载urls, 从而会加载我们写的业务代码(views中的代码); 然后再加载中间件代码. 在应用启动完成时, 所有相关代码都已经被加载入内存。

  • 使用get_wsgi_application(uwisg或gunicorn)方式启动django应用时, 会先加载中间件代码, 这与上面完全相反。 此时, 我们的业务代码仍然没有被加载, 直到第一个请求过来。 如果我们在代码中, 使用了未加载的代码中的全局变量, 就会出现莫名其妙的bug

  • 生产环境下,一般都会设置多个worker(进程),中间件在master进程中加载完成后, 才开始fork子进程, 所以,切勿在中间件中写block的代码, 万一deadlock, 整个服务就挂了。 其实这也是符合Nginx的设计理念的, Nginx的master进程负责处理request信息, 包括处理处理起始行、提取头部、负载等, 然后把请求随机下发到worker进程。同样的, django的中间件也是处理request的, 包括加载session等等。 所以应该把中间件代码放在master进程。

  • 启动时,所有的worker进程都会加载我们的业务代码。 如果某个worker进程, 没有加载过业务代码, 那么当有一个request被下发给它时, 就会去加载。

    由于每个worker进程都会加载一次我们的views代码, 那么就会产生一个问题。如果我们在全局的位置, 做了一些特殊的操作, 比如说开了一个线程, 或者定义一把全局锁, 那么, 在生产环境多进程下, 就会发生, 每个进程都开了一个线程, 或者每个进程都有自己的锁。 之前就遇到过一个bug, 全局位置开了线程去轮询某个资源, 然后写入数据库, 部署到Nginx后, 发现每个item都被写了4次......

  • 还要注意,这些worker之间并不会共享全局变量,在worker A中的修改不会同步到worker B, 必然会出bug

  • 一个worker(进程)可以拥有多个线程,每个线程使用其所属进程的栈空间。同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时,每个线程还拥有自己的寄存器和栈,其他线程可以读写这些栈内存。

  • 一份全局变量只存在于一个python进程中,这个python进程下的子进程可以通过python自带的multiprocess提供的value和array方法共享全局变量。子进程继承父进程的全局变量,而且是以复制的形式完成,所以子进程修改后的全局变量只对自己和自己的子进程有影响。父子进程不共享这些全局变量,也就是说:父进程中对全局变量的修改不影响子进程中的全局变量,同理,子进程也不影响父进程的。

  • uwisg或gunicorn的多worker(进程)与python的一个进程下的多个子进程不是一个层面上的,后者子进程可以通过multiprocess共享全局变量,前者做不到。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基本的 NginxGunicornDjango 和 DRF 示例,涵盖了常见的配置和设置: 1. 安装和配置 Nginx 在服务器上安装 Nginx,并创建一个新的站点配置文件。以下是一个示例配置文件,将所有请求转发到 Gunicorn: ``` server { listen 80; server_name yourdomain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` 2. 安装和配置 GunicornDjango 项目的虚拟环境中安装 Gunicorn: ``` pip install gunicorn ``` 创建一个 Gunicorn 配置文件(比如 gunicorn_config.py),指定项目的 WSGI 应用程序和其他选项: ``` import multiprocessing bind = "127.0.0.1:8000" workers = multiprocessing.cpu_count() * 2 + 1 ``` 3. 安装和配置 Django 和 DRF 在 Django 项目的虚拟环境中安装 Django 和 DRF: ``` pip install django djangorestframework ``` 创建一个 Django 项目,并在 settings.py 中添加 DRF 的应用程序: ``` INSTALLED_APPS = [ ... 'rest_framework', ... ] ``` 在 urls.py 中添加 DRF 的路由: ``` from django.urls import path, include urlpatterns = [ ... path('api/', include('rest_framework.urls')), ... ] ``` 创建一个 DRF 视图(比如 views.py),实现一个简单的 API: ``` from rest_framework.views import APIView from rest_framework.response import Response class HelloWorldView(APIView): def get(self, request): return Response("Hello, World!") ``` 在 urls.py 中添加一个路由,将视图映射到 URL: ``` from django.urls import path from .views import HelloWorldView urlpatterns = [ ... path('api/hello/', HelloWorldView.as_view()), ... ] ``` 4. 启动应用程序 使用 Gunicorn 启动 Django 项目: ``` gunicorn myproject.wsgi:application -c gunicorn_config.py ``` 访问 http://yourdomain.com/api/hello/,应该会看到 "Hello, World!" 的响应。如果您遇到任何问题,请参阅 NginxGunicornDjango 和 DRF 的文档和教程,以获取更详细的说明和指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值