V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hard2reg
V2EX  ›  问与答

如何提升 FastAPI 的 RPS 上限

  •  
  •   hard2reg · 17 天前 · 1124 次点击

    这是我在网站目录下放了返回数据样本(不到 1k),直接通过 Nginx ( 4 个 workers )返回静态文件的压测结果

    wrk -t2 -c750 -d10s https://xxx.com/test.json
    Running 10s test @ https://xxx.com/test.json
      2 threads and 750 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency    39.13ms   61.57ms 793.10ms   96.90%
        Req/Sec    11.84k     1.88k   16.28k    80.46%
      211719 requests in 10.09s, 140.73MB read
    Requests/sec:  20989.41
    Transfer/sec:     13.95MB
    

    于是我又打算测试下裸连 Gunicorn (也是 4 个 workers ),请求一个不到 1k 的 1x1 透明 gif gunicorn -k uvicorn.workers.UvicornWorker -w 4 -b 127.0.0.1:8000 main:app

    TRANSPARENT_GIF = (
        b"\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00"
        b"\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00"
        b"\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b"
    )
    
    @app.get("/api/ping.gif")
    def transparent_image():
        return Response(content=TRANSPARENT_GIF, media_type="image/gif")
    
    wrk -t2 -c750 -d10s http://127.0.0.1:8000/api/ping.gif
    Running 10s test @ http://127.0.0.1:8000/api/ping.gif
      2 threads and 750 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   440.03ms  189.73ms 979.84ms   59.90%
        Req/Sec   846.07    359.59     1.65k    65.13%
      16483 requests in 10.09s, 2.54MB read
    Requests/sec:   1633.21
    Transfer/sec:    257.37KB
    

    Nginx 直接返回数据:20989.41 rps 不反向代理,裸连 Gunicorn:1633.21 rps

    这性能差距也太大了吧?

    第 1 条附言  ·  17 天前
    刚刚用 ai 生成了一个 go 语言的 demo ,真 nb ,1000 并发,3w rps ,学 go 去了
    15 条回复    2025-07-17 17:55:23 +08:00
    chenqh
        1
    chenqh  
       17 天前
    这性能不够吗?
    hard2reg
        2
    hard2reg  
    OP
       17 天前
    @chenqh 目前是够,但是将近 10 倍的性能差距让我难以接受
    PureWhiteWu
        3
    PureWhiteWu  
       17 天前
    要不再试试 Rust ?
    chenqh
        4
    chenqh  
       17 天前
    @hard2reg 动态语言就是这样的啊. 服务器不多的话,没必要换语言.
    darkengine
        5
    darkengine  
       17 天前
    用 gunicorn (python)来处理静态资源本来就是个错误的方案。测性能的话,其实应该用 python/go 分别读数据库返回结果,这样来测 rps 或者说 qps 。
    suruiran
        6
    suruiran  
       17 天前
    等 jit 做好……
    v24radiant
        7
    v24radiant  
       16 天前
    使用异步+uvloop ,在我这边机器 fastapi 的 rps 能提高到原来的 7 倍左右
    hard2reg
        8
    hard2reg  
    OP
       16 天前
    @v24radiant 这个已经是异步的结果了
    hard2reg
        9
    hard2reg  
    OP
       16 天前
    @v24radiant 我刚试了下 uvloop ,rqs 提高了 2 倍。。。
    v24radiant
        10
    v24radiant  
       16 天前
    @hard2reg #8 你需要加 async 吧,我看你上面的贴的代码没加。。。
    hard2reg
        11
    hard2reg  
    OP
       16 天前
    @v24radiant 我测试 uvloop 的时候补上了,只提升了 2 倍
    dongruixuan
        12
    dongruixuan  
       16 天前
    简单测了下 rust ,用的 actix-web 。CPU i5-13600K, 在 WSL 下运行。RPS 1.38M
    ```shell
    wrk -t8 -c750 -d10s http://127.0.0.1:8000/api/ping.gif
    Running 10s test @ http://127.0.0.1:8000/api/ping.gif
    8 threads and 750 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 535.49us 767.36us 14.77ms 90.42%
    Req/Sec 175.31k 19.72k 209.16k 76.43%
    13988354 requests in 10.10s, 2.11GB read
    Requests/sec: 1384945.09
    Transfer/sec: 213.97MB
    ```
    如果 wrk 用 2 线程 750 连接只能打到
    ```
    wrk -t2 -c750 -d10s http://127.0.0.1:8000/api/ping.gif
    Running 10s test @ http://127.0.0.1:8000/api/ping.gif
    2 threads and 750 connections
    Thread Stats Avg Stdev Max +/- Stdev
    Latency 2.05ms 0.98ms 10.72ms 59.25%
    Req/Sec 92.84k 3.88k 98.45k 85.86%
    1851767 requests in 10.10s, 286.09MB read
    Requests/sec: 183347.71
    Transfer/sec: 28.33MB
    ```
    代码如下
    ```rust
    use actix_web;
    use actix_web::{get, App, HttpResponse, HttpServer, Responder};

    const TRANSPARENT_GIF: &'static [u8] =
    b"\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00
    \xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00
    \x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b";

    #[get("/api/ping.gif")]
    async fn transparent_image() -> impl Responder {
    HttpResponse::Ok()
    .append_header(("Content-Type", "image/gif"))
    .body(TRANSPARENT_GIF)
    }

    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
    App::new()
    .service(transparent_image)
    })
    .bind(("127.0.0.1", 8000))?
    .run()
    .await
    }
    ```
    hard2reg
        13
    hard2reg  
    OP
       15 天前
    @dongruixuan nb ,学了 3 天 go 语言,已经被奇葩的语法折磨了
    hard2reg
        14
    hard2reg  
    OP
       15 天前
    @dongruixuan 顺便问一下 wrk -t 后面的数字表示并行数量吧?会如果调大会让 rqs 变大嘛?
    hard2reg
        15
    hard2reg  
    OP
       15 天前
    @hard2reg 打错了 rps
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2818 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 02:33 · PVG 10:33 · LAX 19:33 · JFK 22:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.