
使用Yandex Tank执行测试。
Symfony 4和PHP 7.2被用作应用程序。
目的是比较不同负载下的服务特征并找到最佳选择。
为了方便起见,所有内容都收集在Docker容器中,并使用docker-compose进行募集。
猫下有很多桌子和图表。
源代码在这里 。
本文中描述的所有命令示例都应从项目目录中执行。
应用程式
该应用程序在Symfony 4和PHP 7.2上运行。
仅回答一条路线并返回:
- 随机数
- 环境
- 过程的pid
- 服务所使用的服务的名称;
- php.ini变量。
答案示例:
curl 'http://127.0.0.1:8000/' | python -m json.tool { "env": "prod", "type": "php-fpm", "pid": 8, "random_num": 37264, "php": { "version": "7.2.12", "date.timezone": "Europe/Paris", "display_errors": "", "error_log": "/proc/self/fd/2", "error_reporting": "32767", "log_errors": "1", "memory_limit": "256M", "opcache.enable": "1", "opcache.max_accelerated_files": "20000", "opcache.memory_consumption": "256", "opcache.validate_timestamps": "0", "realpath_cache_size": "4096K", "realpath_cache_ttl": "600", "short_open_tag": "" } }
在每个容器中配置PHP:
日志以stderr编写:
/config/packages/prod/monolog.yaml
monolog: handlers: main: type: stream path: "php://stderr" level: error console: type: console
缓存写在/ dev / shm中:
/src/Kernel.php
... class Kernel extends BaseKernel { public function getCacheDir() { if ($this->environment === 'prod') { return '/dev/shm/symfony-app/cache/' . $this->environment; } else { return $this->getProjectDir() . '/var/cache/' . $this->environment; } } } ...
每个docker-compose都会启动三个主要容器:
- Nginx-反向代理服务器;
- 应用-编写的具有所有依赖项的应用代码;
- PHP FPM \ Nginx单元\ Road Runner \ React PHP-应用程序服务器。
请求处理仅限于两个应用程序实例(根据处理器内核的数量)。
服务项目
PHP流程管理器。 用C写。
优点:
缺点:
使用docker-compose启动应用程序的命令:
cd docker/php-fpm && docker-compose up -d
PHP流程管理器。 它是用PHP编写的。
优点:
- 初始化变量一次,然后使用它们;
- 无需在应用程序中进行任何更改(Symfony / Laravel,Zend和CakePHP有现成的模块)。
缺点:
使用docker-compose启动应用程序的命令:
cd docker/php-ppm && docker-compose up -d
Nginx团队的Application Server。 用C写。
优点:
- 您可以使用HTTP API更改配置。
- 您可以使用不同的配置和语言版本同时运行一个应用程序的多个实例;
- 无需跟踪内存;
- 无需更改应用程序中的任何内容。
缺点:
要从nginx-unit配置文件传递环境变量,您需要修复php.ini:
; Nginx Unit variables_order=E
使用docker-compose启动应用程序的命令:
cd docker/nginx-unit && docker-compose up -d
用于事件编程的库。 它是用PHP编写的。
优点:
- 使用该库,您可以编写一个服务器,该服务器仅初始化一次变量,然后继续使用它们。
缺点:
如果为工作进程使用--reboot-kernel-after-request标志,则将针对每个请求重新初始化Symfony内核。 使用这种方法,您无需监视内存。
使用docker-compose启动应用程序的命令:
cd docker/react-php && docker-compose up -d --scale php=2
Web服务器和PHP进程管理器。 用Golang写。
优点:
- 您可以编写一个只会初始化变量一次并继续使用它们的工作程序。
缺点:
如果为工作进程使用--reboot-kernel-after-request标志,则将针对每个请求重新初始化Symfony内核。 使用这种方法,您无需监视内存。
使用docker-compose启动应用程序的命令:
cd docker/road-runner && docker-compose up -d
测试中
使用Yandex Tank执行测试。
该应用程序和Yandex Tank位于不同的虚拟服务器上。
带有应用程序的虚拟服务器的功能:
虚拟化 :KVM
CPU :2核
内存 :4096 MB
固态硬盘 :50 GB
连线 :100MBit
作业系统 :CentOS 7(64x)
经过测试的服务:
- php-fpm
- php-ppm
- nginx单位
- 道路行人
- road-runner-reboot(带有标志--reboot-kernel-after-request )
- 反应PHP
- react-php-reboot(带有标志--reboot-kernel-after-request )
对于测试1000/10000 rps添加了php-fpm-80服务
使用了php-fpm配置:
pm = dynamic pm.max_children = 80
Yandex坦克会预先确定需要向目标射击多少次,并且直到弹药筒用完才停止。 根据服务的响应速度,测试时间可能会比测试配置中指定的时间更长。 因此,不同服务的图形可能具有不同的长度。 服务响应越慢,其时间表将越长。
对于Yandex Tank的每种服务和配置,仅进行了一项测试。 因此,数字可能不正确。 评估服务相对于彼此的特征非常重要。
100 rps
Phantom Yandex Tank配置
phantom: load_profile: load_type: rps schedule: line(1, 100, 60s) const(100, 540s)
详细报告链接
响应时间百分比
监控方式
图表

图1.1每秒平均响应时间

图表1.2每秒平均处理器负载

图1.3每秒平均内存消耗
500 rps
Phantom Yandex Tank配置
phantom: load_profile: load_type: rps schedule: line(1, 500, 60s) const(500, 540s)
详细报告链接
响应时间百分比
监控方式
图表

图2.1每秒平均响应时间

图2.2每秒平均处理器负载

图2.3每秒平均内存消耗
1000每秒
Phantom Yandex Tank配置
phantom: load_profile: load_type: rps schedule: line(1, 1000, 60s) const(1000, 60s)
详细报告链接
响应时间百分比
监控方式
图表

图3.1每秒平均响应时间

图3.2每秒平均响应时间(无php-fpm,php-ppm,road-runner-reboot)

图3.3每秒平均处理器负载

图3.4每秒平均内存消耗
10000 rps
Phantom Yandex Tank配置
phantom: load_profile: load_type: rps schedule: line(1, 10000, 30s) const(10000, 30s)
详细报告链接
响应时间百分比
监控方式

图4.1每秒平均响应时间

图表4.2每秒平均响应时间(不包括php-fpm,php-ppm)

图4.3每秒平均处理器负载

图4.4每秒平均内存消耗
总结
以下图表显示了根据负载而变化的服务特性。 在查看图表时,值得考虑的是,并非所有服务都可以100%答复请求。

图5.1响应时间的95%

图表5.2 95%的响应时间百分位数

图5.3最大CPU负载

图5.4最大内存消耗
我认为,最佳解决方案(无需更改代码)是Nginx Unit流程管理器。 它在响应速度方面显示出良好的结果,并得到了公司的支持。
无论如何,根据您的工作负载,服务器资源和开发人员的能力,需要分别选择开发方法和工具。
UPD
对于测试1000/10000 rps添加了php-fpm-80服务
使用了php-fpm配置:
pm = dynamic pm.max_children = 80