由 firebase 实时数据库中的写入触发的云功能中的多个连接和巨大的下载开销
multiple connections and huge download overhead in cloud function trigged by writes in firebase realtime database
我在位置 /test/{folder}
中编写了由写入触发的以下云函数 writetest
函数 writetest 只是在位置 /register/{folder} 中写入函数被触发的(近似)时间。
我们可以在 html 文件下面看到 testfirebase.html(我删除了我的项目的信息)。当您在浏览器中加载此 html 时,首先登录该应用程序,然后单击“上传”按钮,在 100 个不同位置 /test/0、/test/1 上传 1KB 数据 100 次, /test/2, ...,/test/99.
当然这会触发云函数writetest 100次。我的问题是,这还会在项目控制台的使用选项卡中生成超过 80 个连接,特别是在项目控制台的“使用”选项卡中,您可以看到大约 440KB 的下载数据。对我来说,完全有下载数据是令人惊讶的,下载数据比上传数据大很多倍更令人惊讶。也许这与每个连接中的 3.5Kb“握手”有关?由于我的真实应用程序经常进行这些上传,并且每次上传都非常小(~1KB),这会显着增加使用由写入触发的云函数的成本。这笔额外费用是不可避免的吗?
这是云函数的代码
exports.writetest = functions.database.ref(
"/test/{folder}")
.onWrite(async (snapshot, context)=> {
return admin.database().ref("/register/"+
context.params.folder).update(
{
"time": admin.database.ServerValue.TIMESTAMP});
});
html 文件testfirebase.html(您必须使用有权写入 /test/ 的用户登录)
<html lang="en">
<head>
<script src=
"https://www.gstatic.com/firebasejs/8.7.0/firebase.js">
</script>
<script src="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.js"></script>
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css" />
<script>
const firebaseConfig = {
apiKey: "XX",
authDomain: "XX.firebaseapp.com",
databaseURL: "https://XX-default-rtdb.firebaseio.com",
projectId: "XX",
storageBucket: "XX.appspot.com",
messagingSenderId: "XX",
appId: "XX",
measurementId: "${config.measurementId}"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var ui = new firebaseui.auth.AuthUI(firebase.auth());
var dbase=firebase.database();
const uiConfig = {
callbacks: {
signInSuccessWithAuthResult(authResult, redirectUrl) {
return true;
},
uiShown() {
},
},
signInFlow: 'popup',
signInSuccessUrl: 'https://mydomain.app/testfirebase.html',
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
],
};
firebase.auth().onAuthStateChanged( async (user) => {
if (user) {
console.log("user logged");
console.log("user id:" +user.uid);
} else {
console.log("no user logged");
ui.start('#firebaseui-auth-container', uiConfig);
}
});
async function dbset(path,data)
{
return new Promise ((resolve,reject)=>{
var reference = dbase.ref(path);
reference.set(data).then(()=>{resolve("OK"); console.log("OK");}).catch((error) => {
reject("ERROR DBSET:"+error);
});
});
}
async function upload()
{
var onekbytestring="";
for (let k=0;k< 1000;k++) {onekbytestring = onekbytestring + "1";}
for (let j=0; j< 100;j++)
{
dbset("test/"+j,{b:onekbytestring });
}
}
</script>
</head>
<body>
<div id="firebaseui-auth-container"></div>
<div >
<button onclick="upload()">Upload</button>
</div>
</body>
</html>
在路径上调用 update
不会 从 path
下载数据。
但是由于您使用 Admin SDK,因此需要通过 HTTPS 建立到服务器的 Web 套接字连接,其中包括建立 TLS/SSL 连接的大约 4Kb 开销。
由于这些客户端连接,每一个也会算作一个连接。这些连接可能会在服务器上停留几分钟,同时等待套接字超时。如果发生这种情况,您还会在控制台中看到这些连接。
请注意,在真实的 use-case 中,连接可能会分散得更多。在这种情况下,我希望您会看到更多 re-use 已建立的连接,因为调用更有可能命中之前使用过的 Cloud Functions 实例,因此 SDK 可能仍具有已建立的连接连接。
您可以尝试使用 REST API 发送更新,看看是否有任何不同。虽然这肯定会减少连接数(因为更新的 REST API 是无连接的),但我怀疑它会对数据大小产生很大影响。尽管如此,如果您担心这一点,还是值得一试。
我在位置 /test/{folder}
中编写了由写入触发的以下云函数 writetest函数 writetest 只是在位置 /register/{folder} 中写入函数被触发的(近似)时间。
我们可以在 html 文件下面看到 testfirebase.html(我删除了我的项目的信息)。当您在浏览器中加载此 html 时,首先登录该应用程序,然后单击“上传”按钮,在 100 个不同位置 /test/0、/test/1 上传 1KB 数据 100 次, /test/2, ...,/test/99.
当然这会触发云函数writetest 100次。我的问题是,这还会在项目控制台的使用选项卡中生成超过 80 个连接,特别是在项目控制台的“使用”选项卡中,您可以看到大约 440KB 的下载数据。对我来说,完全有下载数据是令人惊讶的,下载数据比上传数据大很多倍更令人惊讶。也许这与每个连接中的 3.5Kb“握手”有关?由于我的真实应用程序经常进行这些上传,并且每次上传都非常小(~1KB),这会显着增加使用由写入触发的云函数的成本。这笔额外费用是不可避免的吗?
这是云函数的代码
exports.writetest = functions.database.ref(
"/test/{folder}")
.onWrite(async (snapshot, context)=> {
return admin.database().ref("/register/"+
context.params.folder).update(
{
"time": admin.database.ServerValue.TIMESTAMP});
});
html 文件testfirebase.html(您必须使用有权写入 /test/ 的用户登录)
<html lang="en">
<head>
<script src=
"https://www.gstatic.com/firebasejs/8.7.0/firebase.js">
</script>
<script src="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.js"></script>
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/6.0.1/firebase-ui-auth.css" />
<script>
const firebaseConfig = {
apiKey: "XX",
authDomain: "XX.firebaseapp.com",
databaseURL: "https://XX-default-rtdb.firebaseio.com",
projectId: "XX",
storageBucket: "XX.appspot.com",
messagingSenderId: "XX",
appId: "XX",
measurementId: "${config.measurementId}"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var ui = new firebaseui.auth.AuthUI(firebase.auth());
var dbase=firebase.database();
const uiConfig = {
callbacks: {
signInSuccessWithAuthResult(authResult, redirectUrl) {
return true;
},
uiShown() {
},
},
signInFlow: 'popup',
signInSuccessUrl: 'https://mydomain.app/testfirebase.html',
signInOptions: [
firebase.auth.EmailAuthProvider.PROVIDER_ID,
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
],
};
firebase.auth().onAuthStateChanged( async (user) => {
if (user) {
console.log("user logged");
console.log("user id:" +user.uid);
} else {
console.log("no user logged");
ui.start('#firebaseui-auth-container', uiConfig);
}
});
async function dbset(path,data)
{
return new Promise ((resolve,reject)=>{
var reference = dbase.ref(path);
reference.set(data).then(()=>{resolve("OK"); console.log("OK");}).catch((error) => {
reject("ERROR DBSET:"+error);
});
});
}
async function upload()
{
var onekbytestring="";
for (let k=0;k< 1000;k++) {onekbytestring = onekbytestring + "1";}
for (let j=0; j< 100;j++)
{
dbset("test/"+j,{b:onekbytestring });
}
}
</script>
</head>
<body>
<div id="firebaseui-auth-container"></div>
<div >
<button onclick="upload()">Upload</button>
</div>
</body>
</html>
在路径上调用 update
不会 从 path
下载数据。
但是由于您使用 Admin SDK,因此需要通过 HTTPS 建立到服务器的 Web 套接字连接,其中包括建立 TLS/SSL 连接的大约 4Kb 开销。
由于这些客户端连接,每一个也会算作一个连接。这些连接可能会在服务器上停留几分钟,同时等待套接字超时。如果发生这种情况,您还会在控制台中看到这些连接。
请注意,在真实的 use-case 中,连接可能会分散得更多。在这种情况下,我希望您会看到更多 re-use 已建立的连接,因为调用更有可能命中之前使用过的 Cloud Functions 实例,因此 SDK 可能仍具有已建立的连接连接。
您可以尝试使用 REST API 发送更新,看看是否有任何不同。虽然这肯定会减少连接数(因为更新的 REST API 是无连接的),但我怀疑它会对数据大小产生很大影响。尽管如此,如果您担心这一点,还是值得一试。