Skip to content

把 Robyn 应用送上生产的完整清单 ​

官方文档会告诉你 Robyn 有 --processes、--workers 这些参数,但很少讲"一条生产链路该怎么串起来"。这篇文章按上线顺序整理了一份可照抄的清单:进程数怎么定、要不要挂 Nginx、配置怎么注入、怎么让它开机自启、以及上线前必做的几项检查。

一、先确定进程模型 ​

Robyn 的性能来自 Rust 运行时 + Python asyncio 的组合,参数是这两个词:

  • --processes:操作系统进程数
  • --workers:每个进程内的事件循环线程数

一个稳妥的经验值:

bash
# 4 核机器:进程数 = 核数,workers 保持 1
python app.py --processes=4 --workers=1

# CPU 密集较少、IO 等待较多时,可以适当增加单进程内的 workers
python app.py --processes=2 --workers=4

几个容易踩的点:

  1. 进程数不是越多越好。 Robyn 每个进程都要加载一份 Python 对象和 Rust 运行时,超卖进程会徒增内存占用并加剧上下文切换。
  2. 容器里要留意 CPU 配额。 容器 limits.cpu=2 时,Robyn 读到的可能是宿主机核数。建议显式写死 --processes,别依赖默认值。
  3. 生产环境千万不要带 --dev。 开发模式会开启文件监听,既损耗性能也会把堆栈暴露出去。

最后一个容易忽略的点:多进程之间不共享内存。你在模块顶层定义的可变对象(比如计数器、缓存字典),每个进程都有一份独立副本,count += 1 的结果不会跨进程累加。确实需要在进程间共享时,用 multiprocessing.Value 这类带锁的结构:

python
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:

bash
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 运行 ​

dockerfile
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、压缩、静态资源和限流:

nginx
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 保活(非容器场景) ​

ini
[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.target
bash
sudo 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 的取值是否合理

顺手加一个零依赖的健康检查:

python
from robyn import Robyn

app = Robyn(__file__)

@app.get("/healthz")
def healthz():
    return {"status": "ok"}

小结 ​

Robyn 的上线流程和 FastAPI + Uvicorn 区别不大,真正的差别在于:多进程由框架自己管理,不再需要外部进程管理器去 fork worker。这既简化了运维,也意味着你要亲手把 CPU 配额与实际可用核数对齐。

基于 MIT 许可发布 · 隐私政策