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 /tmp
	RUN 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 中检测 HTTP Server 中的内存泄漏,就需要此全局中间件 */
        Hyperf\SwooleTracker\Middleware\HookMallocMiddleware::class
    ],
];

ps:引入Hyperf\SwooleTracker\Middleware\HttpServerMiddleware::class后会产生的错误

[INFO] HTTP Server listening at 0.0.0.0:9501
zend_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.测试

  1. 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 malloc
		static $arr = [];
		$arr[] =  str_repeat("big string", 1024);
		$GLOBAL['g_arr'][] = str_repeat("big string", 1024);
	}
  1. 运行项目访问demo方法。http://127.0.0.1:9501/index/demo
  2. 查看泄露结果。
    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表示进程 idLoop 5表示第 5 次调用主函数生成的泄漏信息

  • 有确定的内存泄漏的情况:
[217 (Loop 6)] /data/hyperf-skeleton/vendor/hyperf/di/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.php23行,泄露了256字节内存;调用IndexController.php64 行,泄漏了24576字节内存,总共泄漏了 24832 字节内存。

跨 loop 分析:有时本次 Loop 的泄漏会在下次释放掉,Leak工具会跨相邻 2 个Loop 进行分析,自动对冲泄漏信息,如果是跨多个 Loop 的释放,会以如下格式输出:

[195 (Loop 7)] /opt/www/vendor/hyperf/load-balancer/src/AbstractLoadBalancer.php:76 => [-2640]
               Free Pre (Loop 5) : /opt/www/vendor/hyperf/utils/src/Codec/Json.php:49 => [360]
               Free Pre (Loop 5) : /opt/www/vendor/hyperf/rpc-client/src/AbstractServiceClient.php:210 => [2280]

上述信息表示 Loop 7 释放了 Loop 5360+2280 字节内存,如果只算这里,也是没有内存泄漏。

注意事项

  1. 前几次 Loop 的泄漏信息不用管,因为大部分项目都有一些初始化的缓存是不释放的,所以可以先清空下记录。
  2. 检测期间尽量不要有并发。
  3. 由于开启泄漏检测后性能会非常差,不要在 php.ini 中开启apm.enable_malloc_hook = 1压测。
  4. 和 Swoole Tracker2.x 的检查泄漏原理不一样,不能一起用。
  5. 一个进程只能有一个地方调用trackerHookMalloc()函数。
  6. 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 .

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部