Laravel-excel: Masalah Memori dengan Mengimpor File Excel Besar menggunakan Laravel-Excel Chunk Reading

Dibuat pada 18 Apr 2019  ·  21Komentar  ·  Sumber: Maatwebsite/Laravel-Excel

Prasyarat

  • [ X ] Mampu mereproduksi perilaku di luar kode Anda, masalahnya diisolasi ke Laravel Excel.
  • [ X] Memeriksa apakah masalah Anda belum diajukan.
  • [ X] Diperiksa jika tidak ada PR yang dikirimkan yang memperbaiki masalah ini.

Versi

  • Versi PHP: 7.3.3
  • Versi Laravel: 5.8
  • Versi paket: 3.1

Keterangan

Langkah-langkah untuk Reproduksi


Saya memiliki file Excel dengan lebih dari 800.000 catatan yang perlu diimpor.
Saya menggunakan shouldQueue, batchInserts of 1000 dan chunkReading of 1000.
Proses impor tampaknya menempati lebih banyak memori dengan setiap antrian sampai saya kehabisan memori. Saya memiliki server RAM 40GB

Perilaku yang diharapkan:


Bahwa setelah setiap antrian impor selesai, memori yang ditempati dilepaskan sehingga antrian lain dapat menggunakannya.

Perilaku sebenarnya:


Tampaknya dengan setiap antrian, semakin banyak memori yang dikonsumsi sampai seluruh server dimatikan.

informasi tambahan

Informasi, konfigurasi, atau data tambahan apa pun yang mungkin diperlukan untuk mereproduksi masalah.

Saya mencoba mengeluarkan perintah queue:restart setiap kali saya melihat lonjakan memori, dan segera melepaskan banyak memori dan seluruh file dapat diunggah dengan sukses.
Ini hanya pekerjaan sementara yang saya gunakan.

Mungkin terkait dengan https://github.com/Maatwebsite/Laravel-Excel/issues/1391 tetapi solusi yang diberikan tampaknya untuk versi paket yang lebih lama.

Komentar yang paling membantu

@zarapico acara tidak lagi memuat seluruh spreadsheet di memori.
Akan diperbaiki di rilis berikutnya.

Semua 21 komentar

Hai @MakamuEvans apakah Anda bersedia membuat repo dengan pengaturan pengujian yang mereplikasi masalah ini sehingga saya dapat melihat-lihat? Akan membuat ini lebih mudah untuk di-debug, terima kasih!

Hai @patrickbrouwers
Saya memiliki masalah yang sama, ketika mencoba mengimpor CSV sekitar 80000 baris. Dalam kasus saya itu terjadi ketika digabungkan dengan Kontrak ShouldQueue

Ini bekerja:
abstract class BaseImport implements ToModel, WithCustomCsvSettings, WithBatchInserts, WithChunkReading, WithEvents {      use Importable, RegistersEventListeners;      ....

Ini tidak bekerja:
abstract class BaseImport implements ToModel, WithCustomCsvSettings, WithBatchInserts, WithChunkReading, ShouldQueue, WithEvents {      use Importable, RegistersEventListeners;      ....

Terima kasih!

Halo @zarapico pertanyaan yang sama untuk Anda. Bisakah Anda memberi saya contoh repo yang mereplikasi masalah Anda?

Halo @zarapico pertanyaan yang sama untuk Anda. Bisakah Anda memberi saya contoh repo yang mereplikasi masalah Anda?

Halo @patrickbrouwers
Berikut adalah contoh repo: https://github.com/zarapico/Laravel-Excel-MemoryLeak

Ini adalah instalasi laravel 5.8 + yang bersih dan versi repo ini saat ini.

Ada 2 perintah:

  • php artisan excel: importUserFileWithMemoryLeak

  • php artisan excel: importUserFileWithoutMemoryLeak

Saya pikir yang paling penting adalah kebocoran memori terjadi dari peristiwa: https://github.com/zarapico/Laravel-Excel-MemoryLeak/blob/master/app/Imports/UsersImportWithoutMemoryLeak.php#L63 -L77

Terima kasih banyak untuk semuanya

Terima kasih @zarapico

Saya memiliki antrian yang memiliki 100 pekerja, dan karena saya telah memprioritaskan antrian default yang digunakan impor excel, saya perhatikan ada sekitar 50 hingga 60 pekerja yang mencoba memproses file besar.
Sebagai solusi sementara lagi, saya membatasi jumlah pekerja untuk antrian default menjadi sekitar 4~5.
Bagi saya itu berhasil dan file excel 800K saya tidak memakan lebih dari 4GB RAM.

Mungkin info ini bisa membantu.

@zarapico tampaknya masuk akal bahwa 2 peristiwa menyebabkan masalah memori, karena keduanya tampaknya memuat seluruh spreadsheet ke dalam memori. Akan melihat bagaimana kita bisa memperbaikinya.

@MakamuEvans hm, itu menarik. Saya tidak berharap jumlah pekerja memiliki pengaruh di dalamnya, karena pekerjaan dirantai. Apakah Anda menggunakan antrian: kerja atau cakrawala?

Mengapa selama membaca potongan dan menyelesaikan beberapa operasi pada potongan, itu tidak menyadari memori tetapi menyimpannya dalam buffer dan meningkatkannya?

Ada yang aktif di channel ini?
Mengapa pekerjaan ReadChunk membaca seluruh file dari awal hingga akhir, setiap kali untuk setiap potongan?
Itu adalah garis-garis ini:

$spreadsheet = $this->reader->load(
$this->temporaryFile->sync()->getLocalPath()
);

Ini seharusnya hanya membaca baris dari awal chunk hingga baris terakhir dalam chunk.

@mikizdr tidak memuat file dari awal hingga akhir, kami menggunakan filter baca chunk: https://github.com/Maatwebsite/Laravel-Excel/blob/3.1/src/Jobs/ReadChunk.php#L94

Tapi mengapa ChunkReadFilter::readCell menampilkan setiap sel dalam log dari seluruh lembar untuk setiap potongan?
Ini adalah log untuk excel sheet dari 479 baris dan chunk size = 200. Perhatikan pada baris NUMBER OF ROWS (ada 3 baris tersebut) yang berasal dari metode pengumpulan importir dengan perhatian chunkSize.
https://Gist.github.com/mikizdr/d296c2131986e4d72af4e1a479689ffc

Jadi metode readCeil dipanggil untuk setiap sel di seluruh lembar untuk setiap potongan.

Jadi metode readCeil dipanggil untuk setiap sel di seluruh lembar untuk setiap potongan.

Begitulah cara kerja filter baca di PhpSpreadsheet ya.

Tapi itu tidak efisien. Jika Anda memiliki spreadsheet dari 200 ribu baris dan 20 kolom per baris, ukuran potongan = 500, itu akan membaca 400 kali seluruh file dan akan menghabiskan banyak sumber daya. Dalam satu kata - itu akan menguras sistem. Itu harus dioptimalkan dengan cara membaca seluruh file hanya sekali dan setelah itu memindahkan kursor dari titik awal potongan ke titik akhir potongan, memproses data dan melangkah lebih jauh. Itu pendapat saya.

Saya hanya dapat menggunakan fungsionalitas yang ditawarkan PhpSpreadsheet kepada saya. Ini adalah cara yang mereka sarankan untuk digunakan, tidak ada alternatif saat ini.
Karena kedua paket adalah open source, Anda bebas untuk PR solusi yang lebih baik.

Saya bisa melakukan itu tetapi saya perlu kolaborasi untuk beberapa penjelasan terkait dengan kode yang ada. Dan itu harus dilakukan karena optimasi dan efisiensi kode. Menjalankan kode dalam keadaan ini sama sekali tidak baik: memori tidak dioptimalkan, tidak secepat mungkin, pengulangan beberapa langkah yang tidak perlu,...

@zarapico acara tidak lagi memuat seluruh spreadsheet di memori.
Akan diperbaiki di rilis berikutnya.

masalah saya adalah:

saya dapat membaca dan memasukkan ke dalam database satu file dengan 5,8 mb > 140000 catatan. tetapi jika saya menggunakan file dengan catatan 6.1mb 150 000, saya tidak memiliki kesalahan, tetapi halaman itu menyegarkan dan tidak ada yang terjadi ...

di mana saya bisa melihat beberapa kesalahan?

class ClienteImportModel mengimplementasikan ToModel, WithBatchInserts, WithChunkReading, WithEvents
{
gunakan Importable, RegistersEventListeners;

public function model(array $row)
{
   try {

       if (!is_numeric($row[0])) {
           return null;
       }

       return new ClienteTemp([
           'numero' => intval($row[0]),
           'nome' => $row[1],
           'dataContrato' => date('Y-m-d',strtotime($row[2])),
           'cp' => $row[3],
           'idUser' => auth()->user()->id
       ]);
   }
   catch (\Exception $e)
   {
       echo $e;
   }
}


/**
 * <strong i="11">@return</strong> int
 */
public function chunkSize(): int
{
    return 5000;
}

/**
 * <strong i="12">@return</strong> int
 */
public function batchSize(): int
{
    return 5000;
}

}

<<<<<<<<<<<<<<<<<<

Excel::import(New ClienteImportModel(),public_path('/import/excel/Book1b150.xlsx'));

Hai @patrickbrouwers
Saya memiliki masalah yang sama, ketika mencoba mengimpor CSV sekitar 80000 baris. Dalam kasus saya itu terjadi ketika digabungkan dengan Kontrak ShouldQueue

Ini bekerja:
abstract class BaseImport implements ToModel, WithCustomCsvSettings, WithBatchInserts, WithChunkReading, WithEvents {      use Importable, RegistersEventListeners;      ....

Ini tidak bekerja:
abstract class BaseImport implements ToModel, WithCustomCsvSettings, WithBatchInserts, WithChunkReading, ShouldQueue, WithEvents {      use Importable, RegistersEventListeners;      ....

Terima kasih!

di sini tidak berfungsi .... :(

@gordett menyertakan Excel::import.... dengan blok coba/tangkap di dalam pengontrol. Kemudian terapkan penanganan kesalahan di blok tangkap. Try/catch hampir tidak memiliki arti dalam metode model di ClienteImportModel importir.

Hai
saya mencoba dengan mencoba..Tangkap...

masalah saya terselesaikan. adalah server saya ... kehilangan memori ke file besar ...

hihihi

@gordett
halo, saya menghadapi masalah yang sama. dapatkah Anda menunjukkan kepada saya bagaimana Anda telah menerapkan try/catch in controller?
bisakah Anda menempelkan fungsi pengontrol Anda di sini?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat