8.9 KiB
8.9 KiB
可乐平台 异步化架构(ADRF + Granian + PostgreSQL + Nginx)
架构总览
┌──────────┐ :8080 ┌─────────────────────┐
│ 浏览器 │──────────▶│ Nginx (frontend) │
└──────────┘ │ ├─ / → React SPA 静态产物 (build/, 动静分离)
│ ├─ /api 等前缀 ─┐
│ └─ /ws/ ─┤ 反向代理
└──────────────────┼───┘
▼
┌───────────────────────────────┐
│ Granian (Rust) :8000 │
│ Django 5.2 ASGI + ADRF │
│ ├─ 异步视图 (async def) │
│ ├─ 异步 ORM (aget/afilter) │
│ └─ Channels (WebSocket) │
└───────┬──────────────┬────────┘
▼ ▼
┌──────────────┐ ┌──────────────┐
│ PostgreSQL 16 │ │ Redis 7 │
│ psycopg3 异步 │ │ cache/session│
│ ORM 驱动 │ │ celery/ws层 │
└──────────────┘ └──────────────┘
技术选型
| 层 | 技术 | 说明 |
|---|---|---|
| Web 框架 | Django 5.2 + DRF 3.17 | 原生异步能力 |
| 异步视图 | ADRF 0.1.14 | 所有 API 视图跑在异步事件循环上 |
| 应用服务器 | Granian 2.8.2 (Rust) | 替代 Daphne,ASGI + WebSocket,吞吐量显著提升 |
| 数据库 | PostgreSQL 16 | Django 5 异步 ORM 必备(MySQL 后端不支持异步) |
| DB 驱动 | psycopg3 (binary) 3.2.13 | 支持异步连接 |
| 缓存/队列 | Redis 7 | 缓存、Session、Celery broker、Channels layer |
| 前端 | React 19 + Vite 8 | 独立 SPA,与 Django 模板层完全解耦 |
| 反代/静态 | Nginx | SPA 静态资源直出 + API 反向代理 |
关键设计决策
- 全链路异步:视图
async def→ ORMaget/afirst/aexists/acount/acreate/asave/aupdate/adelete→ PostgreSQL(psycopg3)。CONN_MAX_AGE=0(异步 ORM 不支持持久连接)。 - ADRF 兼容性:
view_is_async自动检测处理器;纯 CPU 视图(图形验证码、图像压缩、文本 diff)保持同步def,ADRF 自动sync_to_async线程池兜底。 - 外部 HTTP 调用 aiohttp 化:weather / air_quality / currency / getIpData 全部改为
aiohttp.ClientSession,无阻塞 I/O。 - Redis 缓存 / Celery / SMTP / 密码哈希:同步客户端用
sync_to_async包裹(不阻塞事件循环)。 - 事务兜底:
transaction.atomic+select_for_update段(钱包、任务领取)抽成同步闭包整体sync_to_async执行,保住行锁语义。 - 数据库可切换:
DB_ENGINE环境变量支持django.db.backends.postgresql(默认)与django.db.backends.mysql(本地过渡)。
前后端分离
- 开发:
pnpm dev(Vite HMR :5173),BACKEND_URL环境变量指定后端(默认http://127.0.0.1:8002,Docker 后端用http://127.0.0.1:8000)。API 全部走 Vite proxy,无 CORS 负担。 - 生产:
pnpm build产物由 Nginx 容器直出(try_files → index.htmlSPA 回退),带指纹资源 1 年 immutable 缓存,index.html no-cache。 - 前后端仅通过 RESTful API + WebSocket 交互。
快速开始
一键部署(生产形态)
docker compose up -d --build
# 前端 http://localhost:8080
# 后端 API http://localhost:8000
# Swagger http://localhost:8080/swagger/
本地开发
# 1. 启动数据层
docker compose up -d postgres redis
# 2. 后端(异步栈)
cd chunyu_project
export DB_ENGINE=django.db.backends.postgresql DB_HOST=localhost DB_PORT=5432 \
DB_NAME=chunyu DB_USER=chunyu DB_PASSWORD=chunyu_pg_pass \
REDIS_HOST=localhost
python manage.py migrate
granian --interface asgi --host 0.0.0.0 --port 8000 chunyu_project.asgi:application
# 3. 前端(Vite HMR)
cd chunyu_project_react
BACKEND_URL=http://127.0.0.1:8000 pnpm dev # http://localhost:5173
异步化转换统计
- 覆盖 16 个应用、45 个视图文件:
apiuserarticlelearnchatmessagehistorysearchbugtoolweatherair_qualitycurrencyshorturllogsapidirectoryapp - 处理器全部
async def(约 90+ 个);ORM 调用全部异步化 - 兜底点(
sync_to_async):serializer is_valid/save/data、Redis cache、SMTP/邮件任务、密码哈希、文件存储 I/O、transaction.atomic事务段、Celery.delay - 转换规范见
chunyu_project/docs/ADRF_CONVERSION_GUIDE.md
验证记录
- ✅
python manage.py check0 错误 - ✅ URLCONF 全量导入成功(所有视图模块可加载)
- ✅ Granian 启动 + 冒烟:
/、/article/articles/、/learn/courses/、/api/apidirectory/categories/、/api/weather/?city=Beijing、/api/air-quality/?city=Shanghai、/api/currency/rates/?base=USD、/api/image-captcha/、/api/captcha/generate/、/swagger.json(331KB) 全部 200 - ✅
docker compose config校验通过 - ✅ Nginx 配置语法
nginx -t通过
服务器部署(192.168.5.7 生产/联调环境)
本地 Windows 宿主虚拟化暂时不可用(Hypervisor 未加载,见下),已将整套异步架构部署至本地 Linux 服务器:
| 项 | 值 |
|---|---|
| 服务器 | Debian,16 核(lan-19216857 SSH profile) |
| 部署目录 | /mnt/sda/chunyu |
| 访问地址 | http://192.168.5.7:18080(前端 SPA + API 反代) |
| 后端直连 | http://192.168.5.7:18000(Granian) |
| PostgreSQL | 192.168.5.7:15432(容器内 5432) |
| Redis | 192.168.5.7:16379(容器内 6379) |
端口重映射原因:服务器既有服务占用 5432/6379/8080,覆盖文件 docker-compose.server.yml 将宿主端口改为 15432/16379/18000/18080,容器间通信仍走内部网络不受影响。
部署命令:
cd /mnt/sda/chunyu
docker compose -f docker-compose.yml -f docker-compose.server.yml up -d --build
服务器端到端验证记录(全部通过):
- ✅ 四容器运行:chunyu-backend(healthy) / chunyu-frontend / chunyu-postgres(healthy) / chunyu-redis(healthy)
- ✅ SPA 静态资源 Nginx 直出 200;
/api/apidirectory/categories/、/article/articles/、/swagger.json经反代 200 - ✅ aiohttp 外部 API(天气)经反代 200
- ✅ 异步 ORM 写路径:短链创建成功落库(PostgreSQL 66 张迁移表)
- ✅ Redis PONG(缓存/Session 层)
- ✅ WebSocket:Granian + Channels,JWT 认证后 accept 成功(匿名拒绝为原有业务设计,ChatConsumer 强制认证)
- ✅ 并发冒烟:80 并发 × 5 轮 = 400 请求,400/400 成功,187.9 RPS(穿透 Nginx → Granian → PostgreSQL 全链路)
- ✅ Windows 局域网访问
http://192.168.5.7:18080/*全部 200
说明:
DJANGO_DEBUG插值默认 True(局域网无 TLS;False 会触发SECURE_SSL_REDIRECT301)。正式上 TLS 后设DJANGO_DEBUG=False。 本地 Windows 宿主:2026-09-05 22:22 重启后 HypervisorPresent=False(BCD hypervisorlaunchtype 被关),Docker Desktop 不可用;管理员执行bcdedit /set "{current}" hypervisorlaunchtype auto重启后可恢复本地 Docker。
环境变量
见 docker.env.example。核心项:
| 变量 | 默认 | 说明 |
|---|---|---|
DB_ENGINE |
postgresql | django.db.backends.postgresql / mysql |
DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASSWORD |
postgres/5432/chunyu/chunyu | 数据库连接 |
REDIS_HOST/REDIS_PORT/REDIS_PASSWORD |
redis/6379 | Redis 连接 |
POSTGRES_PASSWORD |
chunyu_pg_pass | PostgreSQL root 密码 |
DJANGO_DEBUG |
False | 生产必须 False |
CORS_ALLOWED_ORIGINS |
localhost:8080/5173 | 前端来源 |
已知限制
- serializer 层仍有同步 ORM(经 sync_to_async 兜底,功能正确但该段走线程池):
chat/serializers.pyConversationSerializer 的 MethodField、bug列表 get_images_count、若干serializer.create()。后续可对 serializer 原生异步化。 - Celery worker 不在默认编排内(views 已适配:同步调用失败自动降级 submit_task 异步队列)。如需启用:
docker compose up -d后手动docker compose run backend celery -A chunyu_project worker -l info。 - Channels ASGI Lifespan 在 Granian 下有 warning(
asginl接口可消除),不影响 WebSocket 功能。 - 纯 CPU 视图(验证码/压缩/diff)保持同步,ADRF 自动线程池兜底。