构建应用服务器时存在一个小众问题。那就是雷电群问题。在这里,我想研究通过在docker环境中启用uwsgi的雷电锁定设置可以改善多少此问题。
什么是雷电群问题?
雷击牧群问题,也称为Zeeg问题,是在多进程和多线程中处理请求时发生的问题。如果一个请求到达并且所有准备好的线程都被唤醒,则资源将被浪费。因为最后通常是一个线程处理一个请求,所以其他线程才被唤醒,确保没有任务,然后再次进入睡眠状态。在当前内核中,可以使同一进程中的线程保持等待锁,以防止唤醒同一进程中的所有线程。但是,如果在进程数量很大时不锁定进程,则会再次发生争用和浪费。
我会验证
我公司的应用服务器是使用nginx uwsgi Django构建的,因此我想验证nginx uwsgi配置的问题。另外,由于我通常在本地环境中玩耍,因此这次我将使用docker构建环境。
验证计划:
答:环境构造(不要输入uwsgi的雷电锁定设置)用k6加载uwsgitop的性能测量
B:环境构造(插入uwsgi的雷锁设置)加载k6使用uwsgitop
进行性能测量
环境建设
首先,使用docker-compose构建一个docker环境,在工作目录中准备以下yml文件
docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 | version: '2' services: web: image: tiangolo/uwsgi-nginx:python2.7 ports: - "30301:80" networks: - "mynet" volumes: - ./workingD:/var/workingD networks: mynet: |
接下来,通过拉
服务启动后(您可以看到uwsgi日志已打印),使用以下命令输入docker
docker exec -it dockusginginx_web_1 /bin/bash<br>
现在,您可以转到该目录并更改nginx和uwsgi设置。
nginx环境设置(/etc/nginx/conf.d/nginx.conf)
可以使用默认设置。
1 2 3 4 5 6 | root@1c30155afc5e:/etc/nginx/conf.d# cat nginx.conf server { location / { include uwsgi_params; uwsgi_pass unix:///tmp/uwsgi.sock; } |
uwsgi环境设置(/etc/uwsgi/uwsgi.ini)
我将多线程设置为4,并将进程数设置为16。我认为这个人(更多过程)将更容易看到雷鸣般的畜群问题。
1 2 3 4 5 6 | [uwsgi] socket = /tmp/uwsgi.sock chown-socket = nginx:nginx chmod-socket = 664 processes = 16 threads = 4 |
uwsgi应用程序设置
在这里,我设置了统计信息的输出目标,以便uwsgitop可以读取性能日志。
1 2 3 4 | [uwsgi] wsgi-file=/app/main.py stats = /var/workingD/stats.sock memory-report = true |
应用逻辑
在uwsgi上运行的应用程序的内容仅返回Hello World,但是它太轻了,因此我将其留给CPU绑定的作业。
1 2 3 4 5 6 7 8 9 10 11 12 13 | def application(env, start_response): workload() start_response('200 OK', [('Content-Type', 'text/html')]) return ["NEWWWWWWW Hello World from a default Nginx uWSGI Python 2.7 app in a\ Docker container (default)"] def workload(): """ provide CPU pound workload """ counter = 1000000 while counter > 0: counter -= 1 |
关于uwsgitop
uwsgitop是用于观察uwsgi性能的工具。
,因为它是python包
1 | pip install uwsgitop |
您可以通过在docker中输入
进行安装。
关于k6
这次我用k6加载,来自python的蝗虫很好,但是我想尝试一个新的,所以k6吗?
要使用k6,首先准备一个脚本
loadtest.js
1 2 3 4 5 | import http from "k6/http"; export default function(){ http.get("http://localhost:30301/"); }; |
在这里,我们定义
要开始负载测试时,可以在
k6 run --vus 64 --duration 0 loadtest.js<br>
在此,让64个虚拟用户(伪用户)执行同时测试脚本。如果
检查结果
验证计划A:
当我运行k6约90秒并获取测量结果时:
uwsgitop
k6
验证计划B:
同样,运行k6约90秒的测量结果:
uwsgitop
k6
结果分析
注意:由于本地环境是4个核心,因此在docker上运行的uwsgi和k6与实际生产环境完全不同。
uwsgitop:计划A的RPS(每秒请求数)在各个进程之间差异很大,有两个RPS为0的进程。 (但这只是瞬时结果的屏幕截图)
似乎没有其他大差异。
k6指标:
http_req_blocked:tcp直到连接初始化的时间
http_req_connecting:是时候与远程主机建立连接了
方案B的上述两项的平均值和最大值较大。
http_req_duration:请求处理时间(不包括块等)。
http_req_waiting:返回请求的第一个响应的时间("到第一个字节的时间")
两项之间的平均值没有太大差异,但Plan B的最大值较小。
比较多个指标,带有雷锁的计划B不能赢得没有计划A的计划。但是,存在诸如响应时间的异常值较小以及uwsgi进程之间处理的请求数量变化较小的优点。