Firebase批量写入25k文档是否触达每秒写入上限?如何限流?
嗨,作为新手能考虑到性能限制这点真的很棒!咱们一步步来拆解你的问题:
一、原代码会触发Firebase写入上限吗?
答案是肯定会。Promise.all(promises)会尽可能并行发起所有25000个写入请求,Firebase Firestore的写入限制是每秒最多10000次操作,这意味着你的代码会在极短时间(远小于1秒)内发起远超上限的请求,最终会导致部分写入失败、被限流,甚至可能触发Firebase的安全机制阻断后续请求。
二、如何把操作分散到不同时间段?
最适合新手的方案是分批处理+延迟间隔,结合Firebase的批量写入API还能进一步优化性能。下面给你两种具体实现方式:
方式1:简单分批并行处理
把25000个用户分成每批9000个(留1000的余量避免触顶),每批处理完后等待1秒以上再处理下一批:
const query = db.collection(`users`) .where("lastActivity","<=",now) .where("lastActivity",">=",last30Days); const usersQuerySnapshot = await query.get(); const userDocs = usersQuerySnapshot.docs; // 每批处理9000个,低于10000的上限 const batchSize = 9000; for (let i = 0; i < userDocs.length; i += batchSize) { // 截取当前批次的用户文档 const currentBatchDocs = userDocs.slice(i, i + batchSize); const promises = []; currentBatchDocs.forEach(userSnapshot => { const user = userSnapshot.data(); const userID = user.userID; const p1 = db.doc(`users/${userID}/inbox/${notificationID}`).set(notificationData); promises.push(p1); }); // 等待当前批次所有写入完成 await Promise.all(promises); // 如果不是最后一批,等待1.1秒再继续(多留100ms确保不超限制) if (i + batchSize < userDocs.length) { await new Promise(resolve => setTimeout(resolve, 1100)); } } return "所有通知已发送完成";
方式2:结合Firebase批量写入(更高效)
Firebase的Batch API允许一次请求处理最多500个写入操作,能大幅减少网络请求次数,同时更容易控制速率。我们可以每20个Batch(对应10000次写入)后等待1秒:
const query = db.collection(`users`) .where("lastActivity","<=",now) .where("lastActivity",">=",last30Days); const usersQuerySnapshot = await query.get(); const userDocs = usersQuerySnapshot.docs; const maxBatchOperations = 500; // Firebase Batch单次最大操作数 const batches = []; let currentBatch = db.batch(); let operationCount = 0; // 先把所有写入操作分配到不同的Batch中 userDocs.forEach((userSnapshot, index) => { const user = userSnapshot.data(); const userID = user.userID; const docRef = db.doc(`users/${userID}/inbox/${notificationID}`); currentBatch.set(docRef, notificationData); operationCount++; // 达到Batch上限或者处理到最后一个文档时,保存当前Batch并重置 if (operationCount === maxBatchOperations || index === userDocs.length - 1) { batches.push(currentBatch); currentBatch = db.batch(); operationCount = 0; } }); // 每20个Batch(对应10000次写入)为一组,组间间隔1.1秒 const batchesPerSecond = 20; for (let i = 0; i < batches.length; i += batchesPerSecond) { const currentBatchGroup = batches.slice(i, i + batchesPerSecond); // 并行执行当前组的所有Batch await Promise.all(currentBatchGroup.map(batch => batch.commit())); // 如果不是最后一组,等待1.1秒 if (i + batchesPerSecond < batches.length) { await new Promise(resolve => setTimeout(resolve, 1100)); } } return "所有通知已发送完成";
额外提醒
- 云函数超时:处理25000个用户大概需要3-4秒(2批9000+1批7000,加两次延迟),远低于云函数默认的90秒超时上限,不用担心超时问题。
- 错误处理:如果需要更稳健,可以在每批处理时加入
try/catch,避免单个失败导致整个任务中断。
内容的提问来源于stack exchange,提问作者Agung
相关产品推荐
相关产品推荐

