批量并发写入Firestore
Write data to Firestore Concurrently in Bulk
我有一个用例,我需要生成一个预先计算的文档并将其保存到 firestore 集合中。
方法是创建一个tasks
集合,每个文档tasks
将用于触发云函数中的onCreate
事件。
每个 onCreate
事件需要大约 40 秒才能完成,然后写入 samples
集合。
需要写入samples
集合的任务数为244 * 26 = 6344个文档。
以下是云函数触发的步骤。
步骤 1:在 tasks
中创建 244 个文档(运行 每 1 小时)
第 2 步:onCreate
将监听事件 -> 生成文档,每个文档大约需要 40 秒。这意味着我们有 244 个函数并发 运行 将 26 个文档文档写入 samples
集合。
我用来写数据的函数
export const generateData = async () => {
const promises = []
for (const sample of samples) {
// some logics
promises.push(sampleRef.set(sampleData))
}
await Promise.all(promises)
return
}
这是我得到的错误:
Error: 4 DEADLINE_EXCEEDED: Deadline exceeded
at Object.callErrorFromStatus (/workspace/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client.js:179:52)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:336:141)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
at /workspace/node_modules/@grpc/grpc-js/build/src/call-stream.js:145:78
at processTicksAndRejections (internal/process/task_queues.js:77:11)
对发生的事情有什么想法或有其他方法吗?谢谢,
这个错误可能有很多原因:
如错误提示,可能与@grpc/grpc-js有关。许多
@google-具有@grpc/grpc-js 依赖项的云库有一个开放的
与并发相关的问题。我读过的唯一有帮助的东西
人们似乎是:
Upgrading your Node version to v13( assuming you are using node as the runtime).
有关详细信息,请参阅 this。
这可能是同时分派多个任务的问题。
临时解决方案是:顺序提交任务。逐个。
可能的解决方法:
设置标志回退:创建任务时为真已解决
一些人的问题。
const {CloudTasksClient} = require('@google-cloud/tasks');
const client = new CloudTasksClient({ fallback: true })
将 fallback 设置为 true 会启用不同的传输(之前的传输)
最初假设用于浏览器) - 而不是使用 gRPC,它
序列化您的请求并通过常规 HTTP/1 连接发送它们
使用节点获取到不同的端点。当您启用回退时,您
根本不执行任何 gRPC 请求 - 它使用完全不同的堆栈。
如果您同时安排许多任务并且执行
Promise.all有大量任务,可以运行争上
资源,这可能会导致 DEADLINE_EXCEEDED.
等问题
如果你有很多任务要排队,我采用的方法如下:
const tasksToCreate = [...]; // an array with a large number of tasks to enqueue.
const WORK_SIZE = 32; // some size of work to perform.
while (work.length > 0) {
const work = tasksToCreate.slice(0, WORK_SIZE).map(() => {
return createTaskPromise();
});
await Promise.all(work);
}
请记住 Firestore 有限制,可能“已超过最后期限”
也可能因为它的局限性而发生。 Maximum write rate to a document is 1 per second. See this。执行太多写入操作太快的人可能会遇到这个问题。现在,当您点击此按钮时,可能会重试写入并可能会降低执行写入的速度可能会有所帮助。
查看here导致此错误的所有其他可能原因
解法:
在 Firestore 上执行大量写入操作的常用方法有 3 种。
- 按顺序执行每个单独的写入操作。
- 使用批量写入操作。
- 并行执行单独的写入操作。
在 Firestore 上执行批量数据写入的最快、最有效的方法是执行并行的单独写入操作。对于批量数据输入,使用 server client library 和并行化的单独写入。您应该使用服务器客户端库进行批量数据操作,而不是 mobile/web SDK。
批量写入的性能优于序列化写入,但不优于并行写入。批量写入通过调用 batch() 创建一个 BatchedWrite 对象,直到它的最大容量为 500 个文档,然后将其写入 Firestore。该解决方案计算对批次进行的每个操作,并在达到限制后创建一个新批次并将其推送到 batchArray。
完成所有更新后,代码循环遍历 batchArray 并提交数组内的每个批次。
重要的是要计算对批处理进行的每个操作 set()、update()、delete(),因为它们都计入 500 个操作限制。
看看这个Whosebug线程对三个写操作的详细分析。
我有一个用例,我需要生成一个预先计算的文档并将其保存到 firestore 集合中。
方法是创建一个tasks
集合,每个文档tasks
将用于触发云函数中的onCreate
事件。
每个 onCreate
事件需要大约 40 秒才能完成,然后写入 samples
集合。
需要写入samples
集合的任务数为244 * 26 = 6344个文档。
以下是云函数触发的步骤。
步骤 1:在 tasks
中创建 244 个文档(运行 每 1 小时)
第 2 步:onCreate
将监听事件 -> 生成文档,每个文档大约需要 40 秒。这意味着我们有 244 个函数并发 运行 将 26 个文档文档写入 samples
集合。
我用来写数据的函数
export const generateData = async () => {
const promises = []
for (const sample of samples) {
// some logics
promises.push(sampleRef.set(sampleData))
}
await Promise.all(promises)
return
}
这是我得到的错误:
Error: 4 DEADLINE_EXCEEDED: Deadline exceeded
at Object.callErrorFromStatus (/workspace/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client.js:179:52)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:336:141)
at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
at /workspace/node_modules/@grpc/grpc-js/build/src/call-stream.js:145:78
at processTicksAndRejections (internal/process/task_queues.js:77:11)
对发生的事情有什么想法或有其他方法吗?谢谢,
这个错误可能有很多原因:
如错误提示,可能与@grpc/grpc-js有关。许多 @google-具有@grpc/grpc-js 依赖项的云库有一个开放的 与并发相关的问题。我读过的唯一有帮助的东西 人们似乎是:
Upgrading your Node version to v13( assuming you are using node as the runtime).
有关详细信息,请参阅 this。
这可能是同时分派多个任务的问题。 临时解决方案是:顺序提交任务。逐个。 可能的解决方法:
设置标志回退:创建任务时为真已解决 一些人的问题。
const {CloudTasksClient} = require('@google-cloud/tasks'); const client = new CloudTasksClient({ fallback: true })
将 fallback 设置为 true 会启用不同的传输(之前的传输) 最初假设用于浏览器) - 而不是使用 gRPC,它 序列化您的请求并通过常规 HTTP/1 连接发送它们 使用节点获取到不同的端点。当您启用回退时,您 根本不执行任何 gRPC 请求 - 它使用完全不同的堆栈。 如果您同时安排许多任务并且执行 Promise.all有大量任务,可以运行争上 资源,这可能会导致 DEADLINE_EXCEEDED.
等问题如果你有很多任务要排队,我采用的方法如下:
const tasksToCreate = [...]; // an array with a large number of tasks to enqueue. const WORK_SIZE = 32; // some size of work to perform. while (work.length > 0) { const work = tasksToCreate.slice(0, WORK_SIZE).map(() => { return createTaskPromise(); }); await Promise.all(work); }
请记住 Firestore 有限制,可能“已超过最后期限” 也可能因为它的局限性而发生。 Maximum write rate to a document is 1 per second. See this。执行太多写入操作太快的人可能会遇到这个问题。现在,当您点击此按钮时,可能会重试写入并可能会降低执行写入的速度可能会有所帮助。
查看here导致此错误的所有其他可能原因
解法:
在 Firestore 上执行大量写入操作的常用方法有 3 种。
- 按顺序执行每个单独的写入操作。
- 使用批量写入操作。
- 并行执行单独的写入操作。
在 Firestore 上执行批量数据写入的最快、最有效的方法是执行并行的单独写入操作。对于批量数据输入,使用 server client library 和并行化的单独写入。您应该使用服务器客户端库进行批量数据操作,而不是 mobile/web SDK。
批量写入的性能优于序列化写入,但不优于并行写入。批量写入通过调用 batch() 创建一个 BatchedWrite 对象,直到它的最大容量为 500 个文档,然后将其写入 Firestore。该解决方案计算对批次进行的每个操作,并在达到限制后创建一个新批次并将其推送到 batchArray。 完成所有更新后,代码循环遍历 batchArray 并提交数组内的每个批次。 重要的是要计算对批处理进行的每个操作 set()、update()、delete(),因为它们都计入 500 个操作限制。
看看这个Whosebug线程对三个写操作的详细分析。