Q: Firebase Extension 限制子节点
Q: Firebase Extension Limit Child Nodes
我是 运行 一个拥有 160k DAU 的 Firebase 应用程序,这是一款在线回合制游戏,使用 RTDB 在玩家之间发送更新。我的数据库负载在最繁忙的时候达到 60% 左右的峰值。
对我来说很长一段时间的问题是如何在比赛结束后“清理”比赛节点。当前结构:
root/games/$gameId
gameId由宿主在匹配过程中提供。之后双方都订阅了这个节点并发送更新。
我能做的是让两个客户端之一在游戏结束后删除节点,但这将是另一个(不可靠的)写入来增加数据库负载。我的主要目标是将“死游戏节点”保持在最低水平,从而降低存储成本(Blaze 计划)。我最近才知道扩展,但我很好奇我的“成本”是多少。
问题 1:此扩展的每次触发都算作对我的数据库的“写入”吗?鉴于一个实例每秒只允许写入 1000 次,这将进一步影响此计数(每秒会触发多次)。
Q2:在 youtube 信息视频中它说它“最适合”自动生成的 ID,但是需要吗? https://www.youtube.com/watch?v=i_u_6RknUro
我知道这个扩展实际上只是一个云函数,但我想知道它在幕后是如何工作的,然后才敢使用它:)
感谢您的帮助:)
所有 Firebase 扩展都是 open-source,因此如果您想了解 限制子节点 扩展的工作原理,您可以查看 source code link from its installation page。
那里的代码:
export const rtdblimit = functions.handler.database.ref.onCreate(
async (snapshot): Promise<void> => {
logs.start();
try {
const parentRef = snapshot.ref.parent;
const parentSnapshot = await parentRef.once("value");
logs.childCount(parentRef.path, parentSnapshot.numChildren());
if (parentSnapshot.numChildren() > config.maxCount) {
let childCount = 0;
const updates = {};
parentSnapshot.forEach((child) => {
if (++childCount <= parentSnapshot.numChildren() - config.maxCount) {
updates[child.key] = null;
}
});
logs.pathTruncating(parentRef.path, config.maxCount);
await parentRef.update(updates);
logs.pathTruncated(parentRef.path, config.maxCount);
} else {
logs.pathSkipped(parentRef.path);
}
logs.complete();
} catch (err) {
logs.error(err);
}
}
);
看起来像这个扩展名:
- 在列表中创建新的子节点时触发。
- 然后读取整个父节点以确定有多少个子节点。
- 然后通过一次写入操作删除超过其最大值的任意数量的子项。
这与我对代码的回忆相符,因为我编写了它的第一个版本。 :)
针对您的问题:
Q1: Would every trigger of this extension count as a "write" to my database?
Cloud Functions 的触发发生在您将子节点写入数据库时。是写入算作写入,触发器本身发生 out-of-band。如果您阅读我链接的其余代码,您会发现它会删除所有超过最大值的子节点作为单次写入。
Q2: In the youtube information video it says it "works best" with auto-generated IDs, but is it needed?
在没有排序条件(const parentSnapshot = await parentRef.once("value")
)的情况下读取节点,然后从该列表的开头删除节点。因此它假定要删除的节点位于列表的开头,这是按它们的键排序的。只要这也适用于您的数据,密钥来自何处并不重要。
我是 运行 一个拥有 160k DAU 的 Firebase 应用程序,这是一款在线回合制游戏,使用 RTDB 在玩家之间发送更新。我的数据库负载在最繁忙的时候达到 60% 左右的峰值。
对我来说很长一段时间的问题是如何在比赛结束后“清理”比赛节点。当前结构:
root/games/$gameId
gameId由宿主在匹配过程中提供。之后双方都订阅了这个节点并发送更新。
我能做的是让两个客户端之一在游戏结束后删除节点,但这将是另一个(不可靠的)写入来增加数据库负载。我的主要目标是将“死游戏节点”保持在最低水平,从而降低存储成本(Blaze 计划)。我最近才知道扩展,但我很好奇我的“成本”是多少。
问题 1:此扩展的每次触发都算作对我的数据库的“写入”吗?鉴于一个实例每秒只允许写入 1000 次,这将进一步影响此计数(每秒会触发多次)。
Q2:在 youtube 信息视频中它说它“最适合”自动生成的 ID,但是需要吗? https://www.youtube.com/watch?v=i_u_6RknUro
我知道这个扩展实际上只是一个云函数,但我想知道它在幕后是如何工作的,然后才敢使用它:)
感谢您的帮助:)
所有 Firebase 扩展都是 open-source,因此如果您想了解 限制子节点 扩展的工作原理,您可以查看 source code link from its installation page。
那里的代码:
export const rtdblimit = functions.handler.database.ref.onCreate(
async (snapshot): Promise<void> => {
logs.start();
try {
const parentRef = snapshot.ref.parent;
const parentSnapshot = await parentRef.once("value");
logs.childCount(parentRef.path, parentSnapshot.numChildren());
if (parentSnapshot.numChildren() > config.maxCount) {
let childCount = 0;
const updates = {};
parentSnapshot.forEach((child) => {
if (++childCount <= parentSnapshot.numChildren() - config.maxCount) {
updates[child.key] = null;
}
});
logs.pathTruncating(parentRef.path, config.maxCount);
await parentRef.update(updates);
logs.pathTruncated(parentRef.path, config.maxCount);
} else {
logs.pathSkipped(parentRef.path);
}
logs.complete();
} catch (err) {
logs.error(err);
}
}
);
看起来像这个扩展名:
- 在列表中创建新的子节点时触发。
- 然后读取整个父节点以确定有多少个子节点。
- 然后通过一次写入操作删除超过其最大值的任意数量的子项。
这与我对代码的回忆相符,因为我编写了它的第一个版本。 :)
针对您的问题:
Q1: Would every trigger of this extension count as a "write" to my database?
Cloud Functions 的触发发生在您将子节点写入数据库时。是写入算作写入,触发器本身发生 out-of-band。如果您阅读我链接的其余代码,您会发现它会删除所有超过最大值的子节点作为单次写入。
Q2: In the youtube information video it says it "works best" with auto-generated IDs, but is it needed?
在没有排序条件(const parentSnapshot = await parentRef.once("value")
)的情况下读取节点,然后从该列表的开头删除节点。因此它假定要删除的节点位于列表的开头,这是按它们的键排序的。只要这也适用于您的数据,密钥来自何处并不重要。