Hyperf下Swoole Tracker的使用
Hyperf下免费版Swoole Tracker使用
公司使用hyperf框架搭建的微服务平台,内存泄露问题十分严重,在排查期间也使用了
gc_mem_caches
回收内存,但是作用不大,所以后面还是采用免费版的Swoole Tracker
作为内存检测工具,帮助排查内存问题;Hyperf的官方文档给的也不是很详细,安装过程也是踩了一些坑;
1. 首先要从官网获取最新的swoole_tracker
包
* 地址 https://business.swoole.com/SwooleTracker/apply* 注意使用和php环境版本一致的 swoole_tracker.so 文件
2. Hyperf
一般使用docker
作为开发容器,这里需要把swoole_tracker相关的扩展以及ini配置打包进dockerfile
;
[swoole_tracker];Tracker从v3.3.0版本开始修改为了Zend扩展zend_extension=swoole_tracker.so;打开总开关 tracker.enable和tracker.enable_malloc_hook不能同时开启tracker.enable=0;采样率 例如:100%tracker.sampling_rate=100;开启内存泄漏检测时添加 默认0 关闭状态tracker.enable_memcheck=1;Leak检测开关tracker.enable_malloc_hook=1
# DockerFile需要增加的内容ADD ./swoole_tracker80.so /tmpRUN cd /tmp \&& cp /tmp/swoole_tracker80.so /usr/lib/php8/modules/swoole_tracker.so \&& echo "zend_extension=swoole_tracker.so" >> /etc/php8/conf.d/swoole_tracker.ini \&& echo "tracker.enable=0" >> /etc/php8/conf.d/swoole_tracker.ini \&& echo "tracker.sampling_rate=100" >> /etc/php8/conf.d/swoole_tracker.ini \&& echo "tracker.enable_memcheck=1" >> /etc/php8/conf.d/swoole_tracker.ini \&& echo "tracker.enable_malloc_hook=1" >> /etc/php8/conf.d/swoole_tracker.ini \
下载好的文件直接放在项目根目录
值得注意的是hyperf官方文档
dockerfile
配置中有一个swoole-tracker-install.sh
文件,免费版用不到这个文件,所以我们忽略掉即可;
3. 依赖组件
composer
安装
composer require hyperf/swoole-tracker
在 config/autoload/aspects.php
配置中间件
return [ 'http' => [ // 这个HttpServerMiddleware就是一个坑,引入后会造成一个报错,在这浪费了很多时间。希望有大佬解答下,是什么地方的问题。在此,我们不引入这个扩展 // Hyperf\SwooleTracker\Middleware\HttpServerMiddleware::class, Hyperf\SwooleTracker\Middleware\HookMallocMiddleware::class ],];
ps:引入
Hyperf\SwooleTracker\Middleware\HttpServerMiddleware::class
后会产生的错误
[INFO] HTTP Server listening at 0.0.0.0:9501zend_mm_heap corrupted[2023-03-03 13:46:39 $67.0] WARNING Server::check_worker_exit_status(): worker(pid=68, id=0) abnormal exit, status=1, signal=0
如果创建目录有以下报错 就需要手动创建目录或者在dockerfile中尝试命令创建
PHP Fatal error: PHP Startup: swoole_tracker extension ERROR: mkdir /opt/swoole/var/run/swoole_tracker/ error,make sure that start the agent first or start your php with root permission(No such file or directory)// 创建目录命令mkdir -p /opt/swoole/var/run/swoole_tracker/
4.测试
- 在
app/Controller/IndexController.php
文件中写一个内存泄漏函数,并调用
public function demo(){$parallel = new Parallel();$parallel->add(function () {$this->foo();sleep(1);return Coroutine::id();});$parallel->add(function () {$this->foo();sleep(1);return Coroutine::id();});try{return $parallel->wait();} catch(ParallelExecutionException $e){print_r($e->getResults()); // $e->getResults() 获取协程中的返回值。print_r($e->getThrowables());// $e->getThrowables() 获取协程中出现的异常。return "exception";}}public function foo(){//如果不需要全局检测 就需要在主函数加上 trackerHookMalloc 用来测试//上面的中间件配置的有全局中间件 Hyperf\SwooleTracker\Middleware\HookMallocMiddleware::class 所以此处不需要单独标记主函数//trackerHookMalloc(); //标记主函数,开始hook mallocstatic $arr = [];$arr[] = str_repeat("big string", 1024);$GLOBAL['g_arr'][] = str_repeat("big string", 1024);}
- 运行项目访问
demo
方法。http://127.0.0.1:9501/index/demo
- 查看泄露结果。
Cli
命令行调用trackerAnalyzeLeak()
函数即可分析泄漏日志,生成泄漏报告;可以直接php -r "trackerAnalyzeLeak();"
Cli
命令行调用trackerCleanLeak()
函数即可可以清除泄漏日志,重新开始;可以直接php -r "trackerCleanLeak();"
5.结果分析
泄漏的信息默认在 /tmp/trackerleak
日志里面
下面是泄漏报告的格式:
- 没有内存泄漏的情况:
[217 (Loop 5)] ✅ Nice!! No Leak Were Detected In This Loop
其中217
表示进程 id
,Loop 5
表示第 5
次调用主函数生成的泄漏信息
- 有确定的内存泄漏的情况:
[217 (Loop 6)] /data/hyperf-skeleton/vendor/hyperf/di/class="lazy" data-src/ClosureDefinitionCollector.php:23 => [256][217 (Loop 6)] /data/hyperf-skeleton/runtime/container/proxy/App_Controller_IndexController.proxy.php:64 => [24576][217 (Loop 6)] ❌ This Loop TotalLeak: [24832]
表示第6
次调用ClosureDefinitionCollector.php
的23
行,泄露了256
字节内存;调用IndexController.php
的 64
行,泄漏了24576
字节内存,总共泄漏了 24832
字节内存。
跨 loop 分析:有时本次 Loop 的泄漏会在下次释放掉,Leak工具会跨相邻 2 个Loop 进行分析,自动对冲泄漏信息,如果是跨多个 Loop 的释放,会以如下格式输出:
[195 (Loop 7)] /opt/www/vendor/hyperf/load-balancer/class="lazy" data-src/AbstractLoadBalancer.php:76 => [-2640] Free Pre (Loop 5) : /opt/www/vendor/hyperf/utils/class="lazy" data-src/Codec/Json.php:49 => [360] Free Pre (Loop 5) : /opt/www/vendor/hyperf/rpc-client/class="lazy" data-src/AbstractServiceClient.php:210 => [2280]
上述信息表示 Loop 7
释放了 Loop 5
的 360
+2280
字节内存,如果只算这里,也是没有内存泄漏。
注意事项
- 前几次 Loop 的泄漏信息不用管,因为大部分项目都有一些初始化的缓存是不释放的,所以可以先清空下记录。
- 检测期间尽量不要有并发。
- 由于开启泄漏检测后性能会非常差,不要在
php.ini
中开启apm.enable_malloc_hook = 1
压测。 - 和 Swoole Tracker2.x 的检查泄漏原理不一样,不能一起用。
- 一个进程只能有一个地方调用
trackerHookMalloc()
函数。 - Swoole4.5.3由于底层 api 有问题,Leak工具无法正常工作,请升级到最新版Swoole或者降级Swoole版本。
一些相关命令
查找PHP扩展目录的位置,
php -i | grep extension_dir
查看swoole和swoole_track版本
php --ri swoole
php --ri swoole_tracker
查询基础环境
uname -a
查询php版本
php -v
cp拷贝命令
cp 源头文件 目标文件
apache的ab压测
ab -n 500 -c 2000 http://10.2.1.28:9501/index/index
docker build
docker build -t swoole_admin_docker:v0.1 .
来源地址:https://blog.csdn.net/github_39327383/article/details/129318227
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341