Django + Celery + Apache mod_wsgi + Postgres + RabbitMQ 多个客户端的应用程序

标签 django apache docker nginx celery

我有一个 Django 应用程序,它使用 Celery、RabbitMQ 和 Apache mod_wsgi。目前全部都在一台服务器上。每个客户端都有自己的URL挂载,例如:

www.example.com/Client001

www.example.com/Client002

www.example.com/Client003

每个客户端都有自己的数据库和项目目录,其中包含用于 Django 设置的 local_setting.py。

我正在使用supervisord 来管理每个客户的 Celery Worker + Celery Beat。

随着我获得越来越多的客户,维护工作也会变得更加耗时。

我已经开始使用 Docker 来尝试简化部署,并可能跨多个主机进行扩展。

虽然设置 Docker Compose 为一个客户端运行一组服务非常容易,但我正在尝试找出易于管理的多个客户端的最佳方法,例如快速设置安装在主 URL 下的新客户端。

我认为 Postgres 数据库实例应该共享以保存每个客户端数据库,就像现在一样。并拥有一个共享的 NGIX 实例来处理 HTTP 端。对于每个客户端,使用一个 Kubernetes Pod,其中包含:

  • Gunicorn 来处理 Django
  • celery 节
  • celery worker
  • 用于静态文件的轻量级 HTTP 服务器。

所以问题是,这是一个好方法还是有更好的方法来处理和处理这个问题?

我还想知道是否应该为每个客户构建一个镜像,因为这样可能更容易管理?

欢迎任何建议。

最佳答案

为此,我的建议是保持一个代码库和一台服务器运行(或同一 Django 应用程序的多个服务器,无需基于客户端进行任何自定义)。主要原因是维护更方便。您不想多次进行更改以向多个客户端提供功能。

由于您已经有一个 Django 应用程序,我认为最好利用该代码来适应上面给出的方法,并且对代码进行最少的更改。这意味着,您需要某种方法来处理连接到多个数据库的多个客户端。我建议是使用中间件和 database router 。像这样:(基于此 snippet 的代码)。

import threading

request_cfg = threading.local()

class RouterMiddleware (object):
    def process_view( self, request, view_func, args, kwargs ):
        if 'client' in kwargs:
            request_cfg.client = kwargs['client']
            request.client = client 
            # Here, we are adding client info with request object.
            # It will make the implementation bit easier because
            # then you can access client information anywhere in the view/template.

    def process_response( self, request, response ):
        if hasattr( request_cfg, 'client' ):
            del request_cfg.client
        return response

class DatabaseRouter (object):
    def _default_db( self ):
        from django.conf import settings
        if hasattr( request_cfg, 'client' ) and request_cfg.client in settings.DATABASES:
            return request_cfg.client            
        else:
            return None

    def db_for_read( self, model, **hints ):
        return self._default_db()

    def db_for_write( self, model, **hints ):
        return self._default_db()

然后将它们添加到settings.py:

DATABASES = {
    'default': {
        'NAME': 'user',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'client1': {
        'NAME': 'client1',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'client2': {
        'NAME': 'client2',
        'ENGINE': 'django.db.backends.postgresql',
        'USER': '_user',
        'PASSWORD': 'priv4te'
    }
}

DATABASE_ROUTERS = [
    'path.to.DatabaseRouter', 
]

MIDDLEWARE = [
    # middlewares
    'path.to.RouterMiddleware'
]

最后更新urls.py:

urlpatterns = [
    path('<str:client>/admin/', admin.site.urls),
    path('<str:client>/', include('client_app.urls')),
    # and so on
]

这种方法的优点是您不必为新客户端配置任何内容,您所需要做的就是在设置中添加新数据库并按照 documentation 中的描述运行迁移。无需配置反向代理服务器或其他任何东西。

现在,当涉及到在 celery 中处理任务时,您可以提供将使用哪个数据库来运行查询(引用 docs )。这是一个例子:

@app.task
def some_task():
    logger.info("-"*25)
    for db_name in settings.DATABASES.keys():
        Model.objects.using(db_name).filter(some_condition=True)
    logger.info("-"*25)

关于Django + Celery + Apache mod_wsgi + Postgres + RabbitMQ 多个客户端的应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63396649/

相关文章:

windows - Windows是否有docker日志查看器或 Debug模式?

django - 部署使用 South 开发的 Django 应用程序堆栈?

python - 即使用户超时, View 也会完成吗?

python - Ubuntu 上的 Django + Apache 部署

apache - .htaccess php 中的重定向规则

mysql - 无法将 Docker Wordpress 容器连接到主机上的 MySQL

python - DetailView 的 Django url 模式

performance - Varnish:仅缓存特定域

php - 为什么PHP脚本在新服务器上执行时间很长?

docker - 如何在travis-ci.com托管的Travis中运行Docker