如何为聊天应用程序分片数据实时数据库?

How to shard data Realtime Database for chat app?

我正在构建一个聊天应用程序并想使用实时数据库。 我希望我的数据库达到配额 200k 同时连接。

所以我已经阅读了documentation关于缩放和分片数据的内容。

但是我不明白如何为聊天应用程序处理这个问题。 假设我有一个 groups 引用,其中包含每个组内的用户 ID 以及该组的消息。

如果我想扩展,我需要创建一个新的数据库实例并开始在那里编写组,因为第一个数据库可能有超过 200k 的同时连接。

这意味着用户可能属于多个数据库中的 groups,这看起来已经很奇怪了,不是一个好主意。

所以我想知道:

这似乎是一种非常复杂的做事方式...我是不是理解不正确?

我确信有很多方法可以对数据库进行分片,但我是这样做的。这涉及在创建新聊天时 select 创建一个碎片。对于这个答案,我们假设有 4 个用户:U1、U2、U3 和 U4,以及 2 个分片(不包括默认分片):shard1 和 shard2。

每当用户创建新聊天时,select 一个分片并为该聊天创建一个新节点。您应该将用户的聊天列表与分片 ID 一起存储在其他地方,默认数据库实例似乎很适合这个,但 Firestore 也可以。因此,包含聊天信息的对象将类似于:

{
  chatID: "c40f15af19a94b6f84117747337b9f7a",
  createdBy: "U1",
  users: ["U1", "U2", "U3"],
  shardId: "shard2"
}

现在您拥有了 chatID 列表及其分片,因此只需连接您的听众即可。同样,这取决于预期的行为是什么。在我的例子中,我只需要收听用户 select 编辑的数据(即活跃聊天)。

尝试在所有分片中平均分配聊天。一个活跃聊天量最少的人(您必须将每个分片创建的聊天数存储在其他地方,例如默认分片)(或者 Round Robin 之类的东西可能有用。同时,将创建聊天的用户考虑在内.

创建新聊天时增加分片中存在的聊天数可能是个好方法。

最后我认为这只是关于如何将聊天分成碎片,并且有许多算法可以使用。如上所述,拥有包含分片名称的用户聊天列表似乎是一种简单的方法。我个人更喜欢 Firestore 来存储聊天列表,这样可以更轻松地根据聊天的创建者、用户 U2 参与的聊天等进行查询。

首选使用 Cloud Function(或您的服务器)创建新聊天,这样就没有人可以通过对应用程序进行逆向工程来向单个数据库碎片发送垃圾邮件。

这样你的所有消息都将存储在实时数据库中,但聊天的基本信息将在 Firestore 中(不是必需的,但更容易查询聊天)。当用户打开聊天应用程序时,加载他们所属的聊天:

这是一个示例 Firestore 文档:

const db = firebase.firestore()
// loading user's chats
const chatsSnapshot = await db.collection("chats").where("members", "array-contains", "myUID").get()

const chatsInfo = chats.map((c) => ({...c.data(), id: c.id}))


// Realtime DB shards
const shards = {
  shard1: firebase.database(app1),
  shard2: firebase.database(app2),
  shard3: firebase.database(app3)
}

// Run a loop on chatsInfo and render chats to your app
for (const chat of chatsInfo) {
  // Limit to first N messages if necessary
  const chatRef = shards[chat.shardId].ref(chat.id);
  chatRef.on('value', (snapshot) => {
    const data = snapshot.val();
    // Render messages
  });
}

您不需要像我上面显示的那样加载所有聊天记录。仅为活跃的聊天加载消息。