使用locust做服务器压力测试

时间:2022-06-03 11:32:00

高并发的性能测试

对于后台的压力性能测试,传统上有jmeter等工具。但这些工具并不能很好地回答一个问题,那就是,我们的服务器能同时支持多少个用户使用?

查看了这篇文章,对比之下,首选locust,原因如下:

  1. python3支持。
  2. 模拟效率高。官方号称单个process可以模拟上千用户的同时操作,有用户提到,通过分布式的方法,模拟了200万用户
  3. 通过python代码可以灵活地处理高并发逻辑。

我个人比较喜欢它的一个理念,qps不等同于同时在线用户数,因为用户可能会等待以判断接下去的操作,所以,这种性能测试的结果,更能接近实际用户的情况。

如何使用locust

查看官方文档,那才是最新最权威的,copy paste不属于本人的风格。需要注意的一点是,对于http的请求,默认情况下,只要返回的status code是 2XX,它就默认请求成功,其他情况会统计为请求失败。可以通过 catch_response 修改默认行为模式。

这边提一些官方文档没提及的东西:

  1. python3的支持。master分支虽然支持,但是pip的包还不支持,需要在requirements里面强行指定alpha版本 locustio >= 0.8a2,或者,通过 pip install git+https://github.com/locustio/locust.git 强行安装master版本
  2. locust本身大量使用了gevent,但是在框架层面没有做 monkey patch,这个会引入 gevent的LoopExit问题。
    测试中使用了concurrent.futures.ThreadPoolExecutor做并发的url访问,结果频繁出现 gevent的LoopExit问题,说 The operation would block forever。ThreadPoolExecutor是按照官方文档写得一模一样的代码,后发现原来是gevent的一个坑,locust内部使用了gevent,但看来并没有做 monkey patch,所以,需要自己在测试代码的开头将这个加上。PS.有些框架在gevent的支持上已经打了monkey patch,比如gunicorn。所以,对于采用 gevent做异步处理的框架,需要了解这个可能忽略的点。

    from gevent import monkey
    monkey.patch_all()

压力测试下发现的问题

  1. 压力下,mysql的使用连接如果不注意释放,很容易用光。(在mysql下面看 show processlist; 可以看到链接数。)
    网上说 SQLAlchemy在多process下的配置比较tricky,看到flask-sqlalchemy有个相关issue。现实代码中,除了通过decorator对于api的调用保证有 db.session.remove()之外(因为采用的是flashalchemy,所以,使用remove()比使用close()更优)。
  2. 大量采用 redis缓存来减少服务器的读,也是一种提高并发量,减少数据库负担的方法。