把 Robyn 应用送上生产的完整清单
官方文档会告诉你 Robyn 有 --processes、--workers 这些参数,但很少讲"一条生产链路该怎么串起来"。这篇文章按上线顺序整理了一份可照抄的清单:进程数怎么定、要不要挂 Nginx、配置怎么注入、怎么让它开机自启、以及上线前必做的几项检查。
一、先确定进程模型
Robyn 的性能来自 Rust 运行时 + Python asyncio 的组合,参数是这两个词:
--processes:操作系统进程数--workers:每个进程内的事件循环线程数
一个稳妥的经验值:
# 4 核机器:进程数 = 核数,workers 保持 1
python app.py --processes=4 --workers=1
# CPU 密集较少、IO 等待较多时,可以适当增加单进程内的 workers
python app.py --processes=2 --workers=4几个容易踩的点:
- 进程数不是越多越好。 Robyn 每个进程都要加载一份 Python 对象和 Rust 运行时,超卖进程会徒增内存占用并加剧上下文切换。
- 容器里要留意 CPU 配额。 容器
limits.cpu=2时,Robyn 读到的可能是宿主机核数。建议显式写死--processes,别依赖默认值。 - 生产环境千万不要带
--dev。 开发模式会开启文件监听,既损耗性能也会把堆栈暴露出去。
最后一个容易忽略的点:多进程之间不共享内存。你在模块顶层定义的可变对象(比如计数器、缓存字典),每个进程都有一份独立副本,count += 1 的结果不会跨进程累加。确实需要在进程间共享时,用 multiprocessing.Value 这类带锁的结构:
import threading
import time
from multiprocessing import Value
from robyn import Robyn
app = Robyn(__file__)
# "i" 表示有符号整数,自带进程/线程级保护
count = Value("i", 0)
def counter():
while True:
count.value += 1
time.sleep(0.2)
@app.get("/hits")
def hits(request):
return {"count": count.value}
threading.Thread(target=counter, daemon=True).start()
app.start()需要更重的共享状态时,与其硬扛,不如直接外置到 Redis——多进程架构下这是更省心也更可水平扩展的做法。
二、配置用 robyn.env 注入,不要写死在代码里
生产环境至少要把 host、port、dev 模式这三项挪进 robyn.env:
ROBYN_HOST=0.0.0.0
ROBYN_PORT=8080
ROBYN_DEV_MODE=False
ROBYN_BROWSER_OPEN=False
ROBYN_MAX_PAYLOAD_SIZE=1000000注意 ROBYN_HOST:容器里必须绑 0.0.0.0,写 127.0.0.1 会导致外部请求进不来——这是本地跑得好好的容器一部署就"连不上"的头号原因。
其余变量说明见 Robyn 环境文件。
三、Dockerfile:多阶段 + 非 root 运行
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.12-slim
RUN groupadd -r robyn && useradd -r -g robyn robyn
WORKDIR /app
COPY --from=builder /root/.local /home/robyn/.local
COPY . .
ENV PATH=/home/robyn/.local/bin:$PATH
USER robyn
EXPOSE 8080
CMD ["python", "app.py", "--processes=4", "--workers=1"]要点:
- 用
--no-cache-dir去掉 pip 缓存,镜像能小几十 MB - Robyn 依赖里有 Rust 编译产物,务必确认你的基础镜像架构与部署机器一致(ARM 机器拉 amd64 镜像会直接启动失败)
四、前面加一层 Nginx
Robyn 自带的 HTTP 服务水平很高,但生产通常还是让 Nginx 处理 TLS、压缩、静态资源和限流:
upstream robyn_app {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
gzip on;
gzip_types application/json text/plain;
# 静态资源交给 Nginx,不要压到 Python 进程上
location /static/ {
root /var/www/app;
expires 7d;
}
location / {
proxy_pass http://robyn_app;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
}
}如果你的项目以 API 为主,静态资源其实可以直接用 app.serve_directory() 由 Rust 层返回,性能不输 Nginx,还能少运维一个组件。两者选其一即可,不要同时做。
五、用 systemd 保活(非容器场景)
[Unit]
Description=Robyn application
After=network.target
[Service]
User=robyn
WorkingDirectory=/srv/myapp
ExecStart=/srv/myapp/venv/bin/python app.py --processes=4 --workers=1
Restart=always
RestartSec=3
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now robyn-app
sudo journalctl -u robyn-app -f六、上线前最后检查
| 检查项 | 为什么重要 |
|---|---|
--dev 已关闭 | 否则会有监听器开销、异常堆栈回显 |
ROBYN_HOST=0.0.0.0 | 容器内默认 127.0.0.1 会导致外部不可达 |
| 健康检查路由已就绪 | 负载均衡需要一个不带认证的存活探针 |
| 日志轮转已配置 | 长期运行日志会持续膨胀 |
限制 ROBYN_MAX_PAYLOAD_SIZE | 防止超大 body 打爆内存 |
| 压测过真实并发 | 验证 --processes 的取值是否合理 |
顺手加一个零依赖的健康检查:
from robyn import Robyn
app = Robyn(__file__)
@app.get("/healthz")
def healthz():
return {"status": "ok"}小结
Robyn 的上线流程和 FastAPI + Uvicorn 区别不大,真正的差别在于:多进程由框架自己管理,不再需要外部进程管理器去 fork worker。这既简化了运维,也意味着你要亲手把 CPU 配额与实际可用核数对齐。