为何仅对Firebase Realtime Database执行写操作就产生12kB/分钟下载流量?
物联网设备启动时运行的代码
//Load data from Global contexta const app = global.get('app'); const database = global.get('database'); const firestore = global.get('firestore'); const auth = global.get('auth'); const firebaseConfig = { //my credentials }; //Set up Firebase const fb_app = app.initializeApp(firebaseConfig); const fb_db = database.getDatabase(); //kdybychom měli vice projektu tak app dame do parametru const fb_ft = firestore.getFirestore(); const fb_auth = auth.getAuth(); //Save the database reference to Global context global.set('fb_app', fb_app); global.set('fb_db', fb_db); global.set('fb_ft', fb_ft); global.set('fb_auth', fb_auth);
每1秒执行的写数据代码
const fb = global.get('database'); const fb_db = global.get('fb_db'); var timestamp = Math.round(msg.payload / 1000); var UID = 'uid1'; var a1 = 0 + Math.floor(Math.random() * 100); var p1 = 50 + Math.floor(Math.random() * 20); var t1 = 20 + Math.floor(Math.random() * 20); //Send data to Firebase const ref = fb.ref( fb_db, 'device_realtime/' + UID + '/' + timestamp.toString() ); fb.set(ref, { a1: a1, p1: p1, t1: t1 });
删除60秒以上旧数据的代码
const fb = global.get('database'); const fb_db = global.get('fb_db'); var timestamp1 = Math.round(msg.payload / 1000) - 60; var timestamp2 = Math.round(msg.payload / 1000) - 61; var UID = 'uid1'; //Delete old data from firebase var reference1 = fb.ref( fb_db, 'device_realtime/' + UID + '/' + timestamp1.toString() ); var reference2 = fb.ref( fb_db, 'device_realtime/' + UID + '/' + timestamp2.toString() ); fb.remove(reference1) fb.remove(reference2)
每1分钟执行的写数据代码
const fb = global.get('database'); const fb_db = global.get('fb_db'); var timestamp = Math.round(msg.payload / 1000); var UID = 'uid1'; var a1 = 0 + Math.floor(Math.random() * 100); var p1 = 50 + Math.floor(Math.random() * 20); var t1 = 20 + Math.floor(Math.random() * 20); //Send data to Firebase const ref = fb.ref( fb_db, 'device_trends/' + UID + '/' + timestamp.toString() ); fb.set(ref, { a1: a1, p1: p1, t1: t1 });
完整流程截图

解答
流量产生的核心原因
观测到的下载流量属于Firebase Realtime Database的正常通信开销,不是异常读操作导致的,主要来源有三个:
- 长连接心跳流量:Firebase Realtime Database采用WebSocket长连接和服务端通信,为了避免连接被网络节点中断,SDK和服务端会定期交换心跳包,这部分流量会被计入下载统计,量级通常在几kB/分钟,和观测数值匹配。
- 写/删除操作的响应流量:每次调用
set、remove方法执行写、删除操作后,服务端都会返回操作状态的确认响应,这部分响应的数据量也会被计入下载流量。每秒执行1次写、2次删除,每分钟额外执行1次趋势数据写,累计的响应流量加心跳,刚好符合12kB/分钟的观测值。 - 安全规则触发的隐性读:如果数据库安全规则中使用了
get()、exists()这类需要读取其他节点数据的校验逻辑,每次写/删除操作触发规则校验时,对应读取的节点数据量也会被计入下载流量。
排查验证方法
- 检查安全规则:先确认实时数据库安全规则中有没有跨节点读的校验逻辑,如果有可以确认这部分流量是否符合预期,也可以调整规则降低不必要的读开销。
- 开启SDK调试日志:在Firebase初始化代码中加入
database.enableLogging(true),开启后可以看到SDK和服务端的所有交互明细,直接确认是否存在未主动调用的读请求。 - 对照测试:暂时停掉所有写、删除操作,只保持设备和Firebase的连接,观测下载流量如果降到3~5kB/分钟的水平,即可完全确认流量来自心跳和操作响应,属于正常现象,无需额外处理。
内容的提问来源于stack exchange,提问作者Jakub Szlaur
相关产品推荐
相关产品推荐

