php进程暴增排查_laravel7 常驻进程 php artisan 业务 内存暴增 详解

laravel7 常驻进程 php artisan 业务 内存暴增 详解

背景

编写了一个常驻进程的脚本结果发现内存在不断上涨最后导致溢出,经过排查发现是日志的问题,之后做了一个测试如下:

for ($i = 0; $i < 1000; $i++) {

Log::info('[INFO]:' . $i);

Log::error('[ERROR]:' . $i);

Log::notice('[NOTICE]:' . $i);

Log::debug('[DEBUG]:' . $i);

if ($i%100==0) {

var_dump(memory_get_usage());

}

}

var_dump(memory_get_usage());

运行结果

4846848

5008736

5118264

5235984

5321256

5422592

5573080

5658032

5742984

5828256

5945368

由结果可以看出内存在不断上涨。

解决办法:

先附上解决办法执行:

一劳永逸

composer remove --dev facade/ignitio

手动释放

app()->make(LogRecorder::class)->reset();

分析过程如下:

1. 先上一个Xhprof对系统进行初筛

附 Xhprof 结果:

57f7530de6917983feb5f079704d7e07.png

ebdc86b180706649cf33f3d8f7337e22.png

分析得出结果是由于logger导致的且与monolog无关。

2. 代码分析

2.1 大胆猜测

根据上图得知问题是由\Illuminate\Log\Logger::writeLog导致

protected function writeLog($level, $message, $context)

{

$this->logger->{$level}($message = $this->formatMessage($message), $context);

$this->fireLogEvent($level, $message, $context);

}

这里有一个事件触发,那么有可能是事件触发导致的。

protected function fireLogEvent($level, $message, array $context = [])

{

// If the event dispatcher is set, we will pass along the parameters to the

// log listeners. These are useful for building profilers or other tools

// that aggregate all of the log messages for a given "request" cycle.

if (isset($this->dispatcher)) {

$this->dispatcher->dispatch(new MessageLogged($level, $message, $context));

}

}

2.2 细致排查

根据fireLogEvent方法得知是对MessageLogged的监听

全局搜索MessageLogged有关的监听逐一排查

该是LogRecorder的问题

be65659f41043e9119196f0fbdfaec49.png

public function register(): self

{

$this->app['events']->listen(MessageLogged::class, [$this, 'record']);

return $this;

}

发现有回调record

public function record(MessageLogged $event): void

{

if ($this->shouldIgnore($event)) {

return;

}

$this->logMessages[] = LogMessage::fromMessageLoggedEvent($event);

}

先将其注释掉看看结果

结果发现内存不再增高,排查问题结束!

2.3 得出结论

结论

$this->logMessages[] = LogMessage::fromMessageLoggedEvent($event);

导致内存增高应该是没有地方释放,再看这个类存在reset

public function reset(): void

{

$this->logMessages = [];

}

2.3.1 方案一:手动释放

那么调用到这个应该就可以了。

app()->make(LogRecorder::class)->reset();

OK,问题解决,但这样不是长久之计。

2.3.1 方案二:一劳永逸

那么需要查找LogRecorder的调用。

在\Facade\Ignition\IgnitionServiceProvider

public function boot()

{

if ($this->app->runningInConsole()) {

$this->publishes([

__DIR__.'/../config/flare.php' => config_path('flare.php'),

], 'flare-config');

$this->publishes([

__DIR__.'/../config/ignition.php' => config_path('ignition.php'),

], 'ignition-config');

}

$this

->registerViewEngines()

->registerHousekeepingRoutes()

->registerLogHandler()

->registerCommands();

if ($this->app->bound('queue')) {

$this->setupQueue($this->app->get('queue'));

}

$this->app->make(QueryRecorder::class)->register();

$this->app->make(LogRecorder::class)->register();

$this->app->make(DumpRecorder::class)->register();

}

protected function setupQueue(QueueManager $queue)

{

$queue->looping(function () {

$this->app->get(Flare::class)->reset();

if (config('flare.reporting.report_queries')) {

$this->app->make(QueryRecorder::class)->reset();

}

$this->app->make(LogRecorder::class)->reset();

$this->app->make(DumpRecorder::class)->reset();

});

}

发现只有Queue才会释放内存。。。。

查找了一圈除了改源码就剩手动不断释放了。

查找这个包的作用,最后发现只是报错展示使用,决定将包删除,问题彻底解决。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值