Firebase读取量突增54k触发配额超限错误原因排查
Firestore 配额超限及读取量异常突增问题排查
问题背景
- 开发场景:基于React搭建简易博客项目,初始开发阶段触发
FirebaseError: Quota exceeded.报错,报错定位到getPosts()函数的Firestore读取逻辑。 - 异常表现:Firebase后台监控面板显示读取量出现异常突增,单次峰值达到54k,直接打满配额上限。
- 涉及代码如下:
import { useEffect, useState } from 'react'; import { getDocs, collection } from 'firebase/firestore'; import { db } from '../firebase-config'; import './Home.css'; const Home = () => { const [postList, setPostList] = useState([]); const postCollectionRef = collection(db, 'posts'); useEffect(() => { const getPosts = async () => { const data = await getDocs(postCollectionRef); setPostList(data.docs.map(doc => ({ ...doc.data(), id: doc.id }))); }; getPosts(); }); return ( <div className="homePage"> {postList.map(post => { return ( <div className="post"> <div className='postHeader'> <div className='post-title'><h1>{post.title}</h1></div> <div className='post-author'><h5>{post.author.name}</h5></div> </div> <div className='post-content'>{post.postText}</div> </div> ); })} </div> ); }; export default Home;
核心疑问
数据遍历的map写法是否是导致短时间内产生5万余次读取操作的原因?
问题根因
map遍历逻辑和读取量突增完全无关,bug来自useEffect的错误使用,形成了无限循环请求:
当前代码中useEffect没有传入第二个参数(依赖数组),React的执行逻辑会进入死循环:
- 组件首次挂载,执行effect回调,发起第一次Firestore集合读取
- 读取完成后调用
setPostList更新组件状态,触发组件重渲染 - 由于没有设置依赖数组,组件每次重渲染都会重新执行effect回调,再次发起读取请求
- 新的读取完成后再次更新状态触发重渲染,循环往复
如果项目开启了React严格模式,开发环境下还会额外重复执行挂载/卸载逻辑,进一步放大请求频次,短时间内累计几万次读取、打满免费配额完全是这个bug的典型表现。
修复方案
给useEffect传入空依赖数组,让getPosts逻辑仅在组件首次挂载时执行1次即可,修改后的effect代码如下:
useEffect(() => { const getPosts = async () => { const data = await getDocs(postCollectionRef); setPostList(data.docs.map(doc => ({ ...doc.data(), id: doc.id }))); }; getPosts(); }, []); // 新增空依赖数组,仅组件挂载时执行一次读取
额外开发建议
- 初始调试阶段优先使用Firebase本地模拟器,所有读写操作不会消耗线上配额,调试效率更高
- 后续博客内容量增长后,不要全量拉取
posts集合全量数据,增加分页逻辑减少无效读取 - 配置合理的Firestore安全规则,避免异常请求无限制消耗配额
内容的提问来源于stack exchange,提问作者Jesse Hickey
相关产品推荐
相关产品推荐

