Skip to content

多实例与负载均衡

说明

当单台服务器无法满足性能需求时,需要通过多实例部署和负载均衡来提升系统吞吐量。本文介绍本项目的水平扩展方案。

Gunicorn 多 Worker 配置

Worker 数量计算

python
# gunicorn.conf.py
import multiprocessing

# 推荐公式:CPU 核心数 * 2 + 1
workers = multiprocessing.cpu_count() * 2 + 1

# Worker 类型
worker_class = 'gevent'  # 异步 Worker,适合 I/O 密集型

# 超时时间
timeout = 120

# 最大请求数(防止内存泄漏)
max_requests = 1000
max_requests_jitter = 50

# 绑定地址
bind = '127.0.0.1:8000'

Worker 类型选择

类型说明适用场景
sync同步 Worker(默认)CPU 密集型
gevent异步 WorkerI/O 密集型(推荐)
uvicornASGI Worker异步框架

Nginx 负载均衡

基础配置

nginx
http {
    upstream djangoadmin {
        # 轮询策略(默认)
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
    }

    server {
        listen 80;
        server_name your-domain.com;

        # 前端静态文件
        root /opt/project/ui/dist;
        index index.html;

        location / {
            try_files $uri $uri/ /index.html;
        }

        # 后端 API 负载均衡
        location /api/ {
            proxy_pass http://djangoadmin;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

负载均衡策略

策略配置说明
轮询默认依次分配请求
权重weight=3按权重分配
IP Haship_hash同一 IP 固定到同一后端
最少连接least_conn分配到连接数最少的后端
nginx
upstream djangoadmin {
    # 权重策略:服务器配置不同按权重分配
    server 127.0.0.1:8001 weight=3;
    server 127.0.0.1:8002 weight=2;
    server 127.0.0.1:8003 weight=1;

    # IP Hash:需要 Session 粘性时使用
    # ip_hash;

    # 最少连接
    # least_conn;

    # 健康检查
    server 127.0.0.1:8001 max_fails=3 fail_timeout=30s;
}

JWT 无状态认证

项目使用 JWT 认证,天然支持多实例部署:

用户请求 → Nginx → 任意后端实例 → 验证 JWT → 返回响应

为什么 JWT 适合多实例

1. 无状态:Token 自包含用户信息,无需服务端 Session
2. 无需共享存储:不需要 Redis 共享 Session
3. 任意路由:请求可以发到任意后端实例
4. 水平扩展:增加实例即可提升性能

Token 黑名单

退出登录时 Token 加入 Redis 黑名单。多实例部署时,所有实例必须连接同一个 Redis,否则 Token 黑名单不生效。

文件存储共享

多实例部署时,上传的文件需要所有实例都能访问:

方案 1:NFS 共享存储

bash
# 服务器挂载 NFS
mount -t nfs storage-server:/data/uploads /opt/project/public/uploads

方案 2:对象存储(推荐)

使用 OSS/S3/MinIO 等对象存储:

python
# 配置对象存储
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_STORAGE_BUCKET_NAME = 'djangoadmin'
AWS_S3_ENDPOINT_URL = 'http://minio:9000'

方案 3:分布式文件系统

使用 Ceph、GlusterFS 等分布式文件系统。

Redis 高可用

多实例部署时,Redis 是关键的共享存储:

Redis Sentinel

python
# 配置 Redis Sentinel
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://sentinel1:26379;redis://sentinel2:26379;redis://sentinel3:26379',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.SentinelClient',
            'SENTINEL_KWARGS': {'sentinel_kwargs': {'password': 'sentinel_password'}},
            'PASSWORD': 'redis_password',
        }
    }
}

Redis Cluster

python
# 配置 Redis Cluster
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': [
            'redis://node1:6379',
            'redis://node2:6379',
            'redis://node3:6379',
        ],
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.ClusterClient',
        }
    }
}

数据库读写分离

Django 配置

python
# application/settings.py
DATABASES = {
    'default': {  # 主库(写)
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'master-db',
        'PORT': 3306,
        'NAME': 'djangoadmin',
        'USER': 'root',
        'PASSWORD': 'password',
    },
    'replica': {  # 从库(读)
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'replica-db',
        'PORT': 3306,
        'NAME': 'djangoadmin',
        'USER': 'root',
        'PASSWORD': 'password',
    },
}

# 数据库路由
DATABASE_ROUTERS = ['config.db_router.MasterSlaveRouter']

数据库路由

python
# config/db_router.py
class MasterSlaveRouter:
    """主从数据库路由"""

    def db_for_read(self, model, **hints):
        return 'replica'

    def db_for_write(self, model, **hints):
        return 'default'

    def allow_relation(self, obj1, obj2, **hints):
        return True

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        return db == 'default'

Supervisor 多实例配置

bash
; /etc/supervisor/conf.d/djangoadmin.conf
[program:djangoadmin-1]
command=/opt/venv/bin/gunicorn application.wsgi:application -c gunicorn.conf.py -b 127.0.0.1:8001
directory=/opt/project
user=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/djangoadmin/worker-1.log

[program:djangoadmin-2]
command=/opt/venv/bin/gunicorn application.wsgi:application -c gunicorn.conf.py -b 127.0.0.1:8002
directory=/opt/project
user=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/djangoadmin/worker-2.log

[program:djangoadmin-3]
command=/opt/venv/bin/gunicorn application.wsgi:application -c gunicorn.conf.py -b 127.0.0.1:8003
directory=/opt/project
user=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/djangoadmin/worker-3.log

[group:djangoadmin]
programs=djangoadmin-1,djangoadmin-2,djangoadmin-3

健康检查

Nginx 负载均衡需要健康检查来自动剔除故障节点:

nginx
upstream djangoadmin {
    server 127.0.0.1:8001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8002 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8003 max_fails=3 fail_timeout=30s;
}

健康检查端点

python
# application/health/views.py
def health_check(request):
    """健康检查端点"""
    try:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
        return JsonResponse({"status": "healthy"})
    except Exception as e:
        return JsonResponse({"status": "unhealthy", "error": str(e)}, status=503)

总结

多实例与负载均衡方案涵盖 Gunicorn 多 Worker、Nginx 负载均衡、JWT 无状态认证、文件存储共享、Redis 高可用、数据库读写分离、Supervisor 多实例配置、健康检查等方面。核心原则:无状态应用 + 共享存储 + 负载均衡。

小蚂蚁云团队 · 提供技术支持