Closed williamhaley closed 1 year ago
Found something interesting this evening. I tried re-running my same tests that earlier performed poorly; those tests saw substantial performance degradation/slow down. This evening though I saw stable reliable performance up to 1,000,000 records for batch writes!
% GCLOUD_PROJECT=fake-project-id ./node_modules/.bin/firebase emulators:start --import=emulator-data --export-on-exit --debug
% NUM_RECORDS=1000000 GCLOUD_PROJECT=fake-project-id FIRESTORE_EMULATOR_HOST=localhost:8080 go run demo.go
...
done writing [994000-994500] 500 result(s) in 0.015791 seconds [rate: 31663.770276/s]
done writing [994500-995000] 500 result(s) in 0.015554 seconds [rate: 32145.534407/s]
done writing [995000-995500] 500 result(s) in 0.017201 seconds [rate: 29067.856061/s]
done writing [995500-996000] 500 result(s) in 0.016630 seconds [rate: 30065.469363/s]
done writing [996000-996500] 500 result(s) in 0.017246 seconds [rate: 28992.293964/s]
done writing [996500-997000] 500 result(s) in 0.016450 seconds [rate: 30394.733979/s]
done writing [997000-997500] 500 result(s) in 0.015604 seconds [rate: 32043.601857/s]
done writing [997500-998000] 500 result(s) in 0.015377 seconds [rate: 32516.010884/s]
done writing [998000-998500] 500 result(s) in 0.015700 seconds [rate: 31847.667257/s]
done writing [998500-999000] 500 result(s) in 0.013916 seconds [rate: 35929.431148/s]
done writing [999000-999500] 500 result(s) in 0.016410 seconds [rate: 30468.366432/s]
done writing [999500-1000000] 500 result(s) in 0.019448 seconds [rate: 25709.745814/s]
I was unable to replicate the poor batch write conditions I'd seen earlier. No matter if I stopped the server, restarted it, it was performing wonderfully. Which is good, but I couldn't figure out what had changed.
THEN, I navigated to the UI in a browser. That is something I had done earlier today in testing when I filed this issue, but did not do in my most recent round of tests. Once I started the emulator and navigated to the firestore UI everything went south and performance immediately took a nose dive.
...
done writing [751500-752000] 500 result(s) in 0.023309 seconds [rate: 21451.152444/s]
done writing [752000-752500] 500 result(s) in 0.024066 seconds [rate: 20776.529436/s]
done writing [752500-753000] 500 result(s) in 0.022594 seconds [rate: 22129.835568/s]
done writing [753000-753500] 500 result(s) in 29.135182 seconds [rate: 17.161383/s]
done writing [753500-754000] 500 result(s) in 59.680087 seconds [rate: 8.378004/s]
...
I can reliably recreate this behavior. As long as the firestore UI is not loaded in a tab performance is wonderful. It's consistent and fast.
The UI seems to be doing something that tanks the firestore emulator and makes it incredibly slow. At least, in my setup it does.
@williamhaley thank you for the detailed digging! The UI establishes multiple connections for the emulator. Some are regular real-time watchers to observer data. It also polls regularly for new collections.
Just to set expectations: it's not our goal to make the emulator "scale" under heavy traffic like a real Firestore instance. It's not meant to be a realistic load testing environment. Actually in most cases it's too fast to be realistic, but you've found an interesting edge case where it's slower than production.
I'll ask around and see if anyone has any ideas here.
Thanks @samtstern!
That totally makes sense regarding expectations. I'm not looking for the emulator to match a real Firestore instance, and to that end I'm totally OK with it being too fast 🚀 . More than anything I'm just interested in being able to see my import scripts run end to end (with a large volume) in a reasonable duration before I run them against production.
For a local developer experience I've tuned my import script to only import the first 1000-ish records of various collections to the firestore emulator just so that some demo data is available. But to test my full import process against prod it's a nice sense of assurance to see the script run through all the records against the emulator and (hopefully) surface any edge cases before hitting production.
Keeping away from the UI is a meaningful workaround on my end to get what I need out of the emulator for that.
@williamhaley I also experience this issue. We are doing batch writes to firestore, about +- 15 000 to 20 000, and it slows down immensely on the emulator, but without the emulator it runs fine. I will test your solution of closing the emulator UI and the give feedback here if that solved it. Thanks for the discovery. I have also noted that once you have a few thousand entries in the Firestore emulator, the collection shows blank, even though the entries are there. Interesting.
Anyways, will give my feedback soon, which might help.
This seems potentially the same issue as #4578; after 10,000 records, the websocket traffic attempting to notify about the records starts throwing errors, and if more records are shoved in after it, the issue could be compounding (the system is spending more and more processing cycles just sending out notifications and can't ingest more records quickly)?
Hey all, while we will do our best to address issues like this, a friendly reminder that the Firestore emulator is not designed for scalability, and it is not expected to handle production-like workloads.
Duplicates https://github.com/firebase/firebase-tools/issues/4578, let's use that one for tracking this issue.
Environment info
firebase-tools:
Platform:
macOS 11.4
Test case
https://github.com/williamhaley/firestore-emulator-slow
Steps to reproduce
npm i
to get dependenciesctrl+c
to kill the client applicationctrl+c
to stop the emulator--debug
Note: The
firebase-debug.log
was not attached as it is very large9.6G Jun 9 11:58 firebase-debug.log
ui-debug.log
Expected behavior
The emulator can sustain a hypothetical real-world bulk import of a large number of documents.
Writes happen at a continuous rate, or the emulator provides meaningful feedback that writes are slowing to the point that the emulator is throwing some data away as it is received.
Actual behavior
The server/emulator becomes unresponsive and slows down over time. Client calls to the emulator return without an error, but the server seems to lose data while writing. The emulator is unusable and must be stopped as it never catches up with the import processing load.