Files
djangoadmin-wiki/DjangoAdmin_Django_EleVue/zh/volume6/scaling.md
T
2026-09-13 17:33:13 +08:00

301 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 多实例与负载均衡
:::tip 说明
当单台服务器无法满足性能需求时,需要通过多实例部署和负载均衡来提升系统吞吐量。本文介绍本项目的水平扩展方案。
:::
## 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` | 异步 Worker | I/O 密集型(推荐) |
| `uvicorn` | ASGI 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 Hash | `ip_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. 水平扩展:增加实例即可提升性能
```
:::warning 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 多实例配置、健康检查等方面。核心原则:无状态应用 + 共享存储 + 负载均衡。