Apa cara tercepat untuk menulis banyak dokumen ke Firestore?

11

Saya perlu menulis sejumlah besar dokumen ke Firestore.

Apa cara tercepat untuk melakukan ini di Node.js?

Frank van Puffelen
sumber

Jawaban:

26

TL; DR: Cara tercepat untuk melakukan pembuatan tanggal massal di Firestore adalah dengan melakukan operasi penulisan individual secara paralel.

Menulis 1.000 dokumen ke Firestore membutuhkan:

  1. ~105.4s saat menggunakan operasi tulis berurutan individual
  2. ~ 2.8s saat menggunakan (2) operasi penulisan batch
  3. ~ 1.5s saat menggunakan operasi tulis individu paralel

Ada tiga cara umum untuk melakukan sejumlah besar operasi penulisan di Firestore.

  1. Lakukan setiap operasi menulis individu secara berurutan.
  2. Menggunakan operasi penulisan batch.
  3. Melakukan operasi penulisan individual secara paralel.

Kami akan menyelidiki masing-masing secara bergantian di bawah ini, menggunakan array data dokumen acak.


Operasi penulisan berurutan individual

Ini adalah solusi yang paling sederhana:

async function testSequentialIndividualWrites(datas) {
  while (datas.length) {
    await collection.add(datas.shift());
  }
}

Kami menulis setiap dokumen secara bergantian, sampai kami telah menulis setiap dokumen. Dan kami menunggu setiap operasi penulisan selesai sebelum memulai yang berikutnya.

Menulis 1.000 dokumen membutuhkan sekitar 105 detik dengan pendekatan ini, sehingga throughput sekitar 10 dokumen menulis per detik .


Menggunakan operasi penulisan batch

Ini adalah solusi paling kompleks.

async function testBatchedWrites(datas) {
  let batch = admin.firestore().batch();
  let count = 0;
  while (datas.length) {
    batch.set(collection.doc(Math.random().toString(36).substring(2, 15)), datas.shift());
    if (++count >= 500 || !datas.length) {
      await batch.commit();
      batch = admin.firestore().batch();
      count = 0;
    }
  }
}

Anda dapat melihat bahwa kami membuat BatchedWriteobjek dengan memanggil batch(), mengisinya hingga kapasitas maksimumnya 500 dokumen, dan kemudian menulisnya ke Firestore. Kami memberikan setiap dokumen nama yang dihasilkan yang cenderung unik (cukup baik untuk pengujian ini).

Menulis 1.000 dokumen memakan waktu sekitar 2,8 detik dengan pendekatan ini, sehingga throughput kira-kira 357 dokumen menulis per detik .

Itu sedikit lebih cepat daripada dengan menulis individu berurutan. Faktanya: banyak pengembang menggunakan pendekatan ini karena mereka menganggap itu tercepat, tetapi karena hasil di atas sudah menunjukkan ini tidak benar. Dan kode sejauh ini yang paling kompleks, karena kendala ukuran pada batch.


Operasi tulis individu paralel

Dokumentasi Firestore mengatakan ini tentang kinerja untuk menambahkan banyak data :

Untuk entri data massal, gunakan pustaka klien server dengan penulisan individual yang diparalelkan. Batched write berperforma lebih baik daripada penulisan berseri tetapi tidak lebih baik dari penulisan paralel.

Kita dapat mengujinya dengan kode ini:

async function testParallelIndividualWrites(datas) {
  await Promise.all(datas.map((data) => collection.add(data)));
}

Kode ini memulai addoperasi secepat mungkin, dan kemudian digunakan Promise.all()untuk menunggu sampai semuanya selesai. Dengan pendekatan ini operasi dapat berjalan secara paralel.

Menulis 1.000 dokumen membutuhkan waktu sekitar 1,5 detik dengan pendekatan ini, sehingga throughput kira-kira 667 dokumen menulis per detik .

Perbedaannya hampir tidak sehebat antara dua pendekatan pertama, tetapi masih lebih dari 1,8 kali lebih cepat dari batch yang menulis.


Beberapa catatan:

  • Anda dapat menemukan kode lengkap dari tes ini di Github .
  • Sementara pengujian dilakukan dengan Node.js, Anda cenderung mendapatkan hasil yang serupa di semua platform yang didukung oleh Admin SDK.
  • Namun, jangan lakukan sisipan massal menggunakan SDK klien, karena hasilnya mungkin sangat berbeda dan jauh lebih mudah diprediksi.
  • Seperti biasa kinerja aktual tergantung pada mesin Anda, bandwidth dan latensi koneksi internet Anda, dan banyak faktor lainnya. Berdasarkan yang Anda mungkin melihat perbedaan dalam perbedaan juga, meskipun saya berharap pemesanan tetap sama.
  • Jika Anda memiliki pencilan dalam tes Anda sendiri, atau menemukan hasil yang sama sekali berbeda, tinggalkan komentar di bawah ini.
  • Batch menulis adalah atom. Jadi, jika Anda memiliki dependensi antara dokumen dan semua dokumen harus ditulis, atau tidak ada yang harus ditulis, Anda harus menggunakan tulisan batch.
Frank van Puffelen
sumber
1
Ini super menarik, terima kasih telah melakukan pekerjaan! OOC, apakah Anda menguji menjalankan menulis batched secara paralel? Jelas, dalam hal ini Anda perlu lebih yakin untuk menghindari dokumen yang berada di kedua batch.
robsiemb
1
Saya akan menguji menulis batch paralel, tetapi kehabisan kuota (ini adalah proyek gratis, dan saya terlalu malas untuk meng-upgrade). Hari ini adalah hari lain, jadi saya dapat mencobanya, dan memperbarui jawaban saya jika itu penting.
Frank van Puffelen
2
@robsiemb Saya baru saja menguji dengan menulis paralel juga. Performanya sangat mirip dengan tulisan paralel individu, jadi saya akan mengatakan mereka terikat untuk pertama kali dalam tes saya. Saya berharap bahwa penulisan batch dapat memburuk lebih cepat karena sifat mereka diproses di back-end. Dikombinasikan dengan kode yang jauh lebih kompleks, saya masih merekomendasikan hanya menggunakannya untuk atomicity mereka dan bukan keuntungan kinerja yang dirasakan-tetapi-tidak-ada.
Frank van Puffelen
@FrankvanPuffelen menulis yang diparalelkan akan lebih cepat juga jika saya "mengatur" dokumen daripada "menambahkan" dokumen? Maksud saya, db.collection ('cities') .doc ('LA'). Set (data) alih-alih db.collection ('cities'). Tambahkan (data)
alek6dj
Memanggil add()tidak lebih dari menghasilkan ID unik (murni sisi klien), diikuti oleh set()operasi. Jadi hasilnya harus sama. Jika bukan itu yang Anda amati, kirimkan pertanyaan baru dengan case minimal yang mereproduksi apa yang telah Anda coba.
Frank van Puffelen