编辑
2023-04-20
测试平台
00
请注意,本文编写于 319 天前,最后修改于 319 天前,其中某些信息可能已经过时。

目录

1、背景
2、发现问题
3、排查问题
3.1 排查gunicorn命令
3.2 排查Python基础镜像
4、验证问题
5、思考
6、总结

1、背景

近期,我决定将测试平台迁移到国外的 VPS 上。由于 VPS 的配置相当有限,只有 2G 的内存,而且已有多个服务在上面运行,内存占用已达 70%多。在如此紧张的资源环境下,降低测试平台后端的线程数量,期望能减少资源占用。

原来的启动命令是:

# 容器中django启动命令,使用gunicorn默认的worker pool(同步) # -w4 起4个worker /usr/local/bin/python -m gunicorn FasterRunner.wsgi_docker -b 0.0.0.0 -w4

image-20230420111105635

修改后的启动命令是:

# 容器中django启动命令,使用gunicorn默认的worker pool(同步),默认起1个worker /usr/local/bin/python -m gunicorn FasterRunner.wsgi_docker -b 0.0.0.0

image-20230420110714548

内存确实有明显的下降,少了200M+,对于内存捉急的小机器,还是相当可观!

2、发现问题

但是!!!在修改后,验证发现请求外部接口是正常的,请求测试平台内部接口时会发生超时现象。
用celery异步执行用例,定时任务啥的都没问题
这让我百思不得其解,心中充满了困惑。看完 log 之后,还是无法找到问题所在。

你看请求外部接口,妥妥的 image-20230420093217587

请求测试平台内部接口,执行超时

image-20230420093342831

3、排查问题

3.1 排查gunicorn命令

第一个怀疑的对象就是gunicorn命令,但想了一下,请求外部接口是好的啊,平台接口都能正常的跑;请求测试平台内部才有问题,那会不会是基础镜像问题?

3.2 排查Python基础镜像

第二个怀疑对象是 Python 基础镜像。尽管我之前从 python-alpine 更换为 python-buster 已经验证过,但我决定在本地再次尝试回滚到 python-alpine。(至于为什么更换镜像,那又是另一个事情了)
然而,问题仍然存在。这让我更加困惑,因为目前部署在腾讯云就是用python-alpine,在海外vps使用的python-buster,两个明明可以正常运行。

这就有点尴尬了啊,似乎都没啥问题,只是请求测试平台内部接口有问题。 要不先这样就发布算了,反正正常使用都是请求外部接口,没啥影响? 开玩笑,那当然不行,明显不符合我的风格呀!况且演示demo就是请求内部接口啊!

4、验证问题

于是在 ChatGPT 上查询了 Gunicorn 的 worker pool,发现默认的 worker 是 1,并且是同步的。

image-20230420093630179

这时,我觉得问题可能出在这里。我回想起在虾皮工作时,Django 项目也是使用 Gunicorn 部署,并且 worker pool使用的是协程,这样更节省资源。于是,我决定尝试使用 Gunicorn + 协程 worker 的方式。

shell
# 容器中django启动命令,使用gunicorn + gevent worker pool(异步) # -w4,启动4个worker /usr/local/bin/python -m gunicorn FasterRunner.wsgi_docker -b 0.0.0.0 -w4 -k gevent

果不其然,问题得到了解决! 请求外部接口和测试平台内部接口都是妥妥的!

image-20230420094224385

我立刻兴奋起来,再次切换回单线程启动命令,发现问题可以复现。证实问题确实出在 worker 这里。

经过深思熟虑,我意识到了问题的关键所在:

单线程的同步 worker 只能同时处理一个请求。执行API测试时就占用了一个线程,这时已经没有多余的线程来处理其他请求,刚好这个API测试恰好请求到了内部接口,所以这个请求就只能在那里干等,直到最后超时失败!

并且这期间,整个测试平台的所有接口都无法处理,都会卡住!!!

5、思考

那么问题了,gunicorn worker pool换成协程之后,4个worker是完全没问题的

shell
# 容器中django启动命令,使用gunicorn + gevent worker pool(异步) # -w4,启动4个worker /usr/local/bin/python -m gunicorn FasterRunner.wsgi_docker -b 0.0.0.0 -w4 -k gevent

就是占用资源还是有点高(刚启动的状态,184M)

image-20230420095940802

如果换成gunicorn worker pool换成协程之后,只有1个worker,那会有问题吗?

亲自来验证一波吧

https://fast.huacai.one/fastrunner/login
账号: test
密码: test2020

shell
# 容器中django启动命令,使用gunicorn + gevent worker pool(异步) # -w1,启动1个worker /usr/local/bin/python -m gunicorn FasterRunner.wsgi_docker -b 0.0.0.0 -w1 -k gevent

占用资源少了一半,对于内存不足的小鸡,90M也很香呀!

image-20230420095156709

6、总结

  • 出问题先从最近的改动开始排查,先回滚再说

本文作者:花菜

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!