Python Web 应用并发测试

网上常听到这样一种论调:Python 太慢,因而不适合做 Web 开发。为了详细了解 Python 在实用场景下的性能,笔者做了一个简单的博客系统,支持简单的博客展示,提供上传、修改的接口,然后尝试在迭代过程中提高并发性能。

项目已开源在 GitHub。这个系统最终的实现是 MongoDB + Redis + local cache 作为分级存储,尽可能使用异步逻辑,使用 Uvicorn 的多进程提高效率。为了直观地看到性能的变化,本文按照倒序的方式来编排。

测试的具体实现就是用 locust 模仿若干用户并发访问一个指定的博客,见项目下的 bench.py 文件。

测试硬件条件:

  • CPU:2 核
  • 内存:2GB
  • 带宽:100Mbps

性能极限

用最终实现测得极限性能,前期最大 RPS 在 2500 左右,然后系统变得非常不稳定,此时有 2000 个用户。因此以下测试均使用 1000 个用户作为测试条件。

最终实现

ef25cb1

  • RPS ~ 2300
  • RTp50 ~ 200ms
  • RTp95 ~ 1300ms

后面一段异常的数据可能是压测主机不太稳定。

移除本地缓存

84f2587

  • RPS ~ 1300
  • RTp50 ~ 300ms
  • RTP95 ~ 3300ms

本地缓存(local cache)其实就是 Python 里一个字典类型的全局变量。移除后的最高层级缓存是 Redis 实例,在读取数据时必须经过网络通信,所以这里的性能下降了很多。

中间一段异常数据原因暂未知,忘记拿日志了😭

移除 Redis 缓存

b2b6168

  • RPS ~ 1000
  • RTp50 ~ 300ms
  • RTp95 ~ 3300ms

移除 Redis 缓存后,所有读请求必须经过 MongoDB 数据库,但是这里的 RPS 并没有降低多少。猜测原因是无论从 Redis 读还是从 MongoDB 读,大部分的时间都花在了网络通信上。

把 MongoDB 换成 Postgres

9ae9101

  • RPS ~ 510
  • RTp50 ~ 2000ms
  • RTp95 ~ 5000ms

MongoDB 属于 NoSQL 数据库。相比于传统的关系型数据库,NoSQL 不支持事务,没有 Schema,只保证最终一致性,好处是带来了一定的性能提升。可以看到把数据库换成关系型数据库后,性能显著下降。

当然 Postgres 也有 NoSQL 特性,这里没有启用。

多进程变单进程

29fc343

  • RPS ~ 220
  • RTp50 ~ 4000ms
  • RTp95 ~ 12000ms

服务器只有两个核心,这里我只开了两个进程。变成单进程后性能确实减半了。

移除异步

fae58bb

  • RPS ~ 180
  • RTp50 ~ 6000ms
  • RTp95 ~ 6000ms

这个结果比较奇怪,为什么移除异步后 RPS 变化还没有 RTp95 变化大。

监控

最后附上服务器的监控。

Author: HairlessVillager

Permalink: http://hairlessvillager.github.io/2024/08/11/benchtest-on-python-web-application/

The article is licensed under the CC BY-NC-SA 4.0 protocol by default.

Please comply with the protocol when using it.