关于Laravel 队列内存的一个占用大小的设置[问题已测试解决]
大数据导出扩展推荐:
评论里推荐的这个也不错 最原始的
xlswriter
我把这几个测试截图都放到一起,大家参考使用
fast-excel-writer
这个需要安装扩展,也很快
php-ext-xlswriter
最近在测试laravel queue database
驱动时候,使用 queue:work
频繁退出,发现是队列执行的内存 memory = 128M
超了, 实际队列内部执行下来是144M ,所以造成了队列的频繁退出
队列内存大的起因: 系统导出大量的数据,结果是Excel ,采用异步 + queue 的方式进行到处,每个Excel 限制是 5000 条数据,里面涉及到ORM 模型的查询,采用的方式都是ID chunkById 方式,字段也限制了
问题:想问问大家的excel 在处理这种单个队列内存过大,有设置过内存大小没,具体这个东西怎么来评判合适
我的目前方案:减少项目的ORM 调用, 尽量使用 lazycollection
缩小内存:
伪代码:
$chunks = ApplyRisk::getListQuery(ApplyRiskFilter::apply($params, 'beforeLoan'))
->select(['apply_risk_id'])
->lazyById(2000)
->chunk(5000);
$this->task->update([
'status' => TaskStatusEnum::ready()
]);
$jobs = [];
foreach ($chunks as $key => $chunk) {
$ids = $chunk->pluck('apply_risk_id')->toArray();
$jobs[] = new BeforeLoadExportBatchJob($this->task, LazyCollection::make($ids), $key + 1);
}
unset($chunks);
$batch = Bus::batch($jobs)
// 所有任务完成才执行的回调
->finally(function (Batch $batch) {
//if ($batch->finished()) {
// $this->task->update([
// 'status' => TaskStatusEnum::finished()
// ]);
//}
})->dispatch();
使用了Larvle 内置的批处理队列代码:Bus::batch
现在我遇到的问题是每个batch job
需要处理的数据量也就5000 条,但是还是会造成队列 quit, 指定参数:queue:work --memory=256
问题虽然能解决,但并不是我最想要的,我是想问下在大量数据下,分块情况下如果更大程度的节省内存
解决方案来了
查了资料,解决方案如下
解决方案来了:
目前单次导出大概数据量在2-5万附近 队列采用 database 驱动
导出的扩展用的是 fast-excel
主队列
$jobs = [];
$chunks = ApplyRisk::getListQuery(ApplyRiskFilter::apply($params, 'beforeLoan'))
->select(['apply_risk_id'])
->chunkById(5000, function ($rows, $page) use (&$jobs) {
$ids = $rows->pluck('apply_risk_id')->toArray();
$jobs[] = new BeforeLoadExportBatchJob($this->task, LazyCollection::make($ids), $page + 1);
});
unset($chunks);
Bus::batch($jobs)
// 所有任务完成才执行的回调
->finally(function (Batch $batch) {
//if ($batch->finished()) {
// $this->task->update([
// 'status' => TaskStatusEnum::finished()
// ]);
//}
})->dispatch();
unset($jobs);
批次队列导出Excel:
节省核心内存在这,采用 yield 生成器的方式传入
//数据准备完毕,开始导出
FastExcel::data($this->genertateLazyData($this->riskIds))->export($fileName);
public function genertateLazyData($chunks)
{
/** @var \Illuminate\Support\LazyCollection $chunk */
// 省略了 select 此处
yield from ApplyRisk::whereIn('apply_risk_id', $chunks)->lazy()->each(function ($row) {
yield $this->transform->beforeLoan($row);
});
}
内存占用情况:
使用内存记录方式:
// 单位是M
Log::info('Batch队列内存记录:'. memory_get_usage(true) / 1024/ 1024);
解决方案参考上文,如果有需要的朋友可参考,目前单次导出数据量在2-5万, 采取的方案是批量导出一次5000 条 最终在压缩到一起提供下载,使用的扩展是 fast-excel ,最终导出数据采用的是
yield
生成器方式,laravel queue 默认 memory = 128M 直接导出 一直在144M 附近,导出一次队列就停止了, 这种方式可以限定单个队列的内存稳定在50M附近,导出完毕,释放变量