使用多个数据库进行扩容

如需在 Firebase Realtime Database 中优化性能和扩大数据规模,最佳方法是将数据拆分到多个 Realtime Database 实例中,也称为数据库分片。除了负载平衡和性能优化之外,分片还赋予您扩容的灵活性,不再受单个数据库实例限额的限制。

何时进行数据分片

如果您要在以下任一情况下使用 Realtime Database,建议您最好将数据分片到多个数据库中:

  • 您希望将单个数据库实例扩大到超过 20 万个并发连接、每秒 1000 次写入操作的限额,或超过其他任何限额
  • 您有多个互不关联的数据集,并希望优化性能(例如,为各自独立、互不相关的用户组提供服务的聊天应用)。
  • 您希望在多个数据库之间平衡负载,以改善正常运行时间并降低单个数据库实例负载过大的风险。

如何进行数据分片

如需将数据分片,请按照以下步骤操作(后面有详细介绍):

  1. 根据您的应用的具体需求将数据映射到多个数据库。
  2. 创建多个数据库实例。
  3. 配置您的应用,使其连接到每个数据集所需的 Firebase Realtime Database 实例。

映射您的数据

在将数据映射到多个数据库时,请尽量满足以下条件:

  • 每个查询仅针对单个数据库实例来执行。Firebase Realtime Database 不支持跨数据库实例的查询。
  • 数据库实例之间不存在共享或重复的数据(或只有极少的共享或重复数据)。
  • 无论何时每个应用实例都只连接到一个数据库。

在映射数据时,您不妨考虑应用以下策略:

创建一个“主分片”

存储您的数据在各个数据库实例中的存储情况的映射。这样,您就能以编程方式查找与连接的客户端对应的数据库实例。请注意,与在您需要时直接连接您所需的特定数据库实例相比,此策略的开销可能会更大。

按类别或客户分区存储数据

按用户或数据类型对数据进行分组,并分别存储在多个独立数据库实例中。 例如,如果您要构建一个为多个组织提供服务的聊天应用,则可以为每个组织创建一个数据库实例,并将各个组织的所有聊天数据存储到各自对应的唯一数据库实例中。

在这种情况下,A 组织和 B 组织不共享数据,这些数据库中没有任何重复的数据,并且您只针对单个数据库实例执行查询。此外,每个组织中的用户只有在使用该聊天应用时才会连接到其组织的数据库。

这样的话,您可以预先创建多个数据库实例,并使用组织的 ID 将某个团队映射到其数据库实例。例如,A 组织映射到 Firebase Realtime Database A。

您为应用映射数据的方式取决于具体的使用情形,但上述条件和策略可以帮助您确定适合您的数据的方式。

创建多个 Realtime Database 实例

如果您使用的是 Blaze 定价方案,则可以在同一个 Firebase 项目中创建多个数据库实例。

在 Firebase 控制台中使用“数据库”部分的上下文菜单创建数据库

  1. 在 Firebase 控制台中,转到开发 > 数据库部分的数据标签页。
  2. Realtime Database 部分的菜单中选择创建新数据库
  3. 自定义数据库引用安全规则,然后点击知道了

您可以重复上述过程,根据自己的需要创建任意多个数据库实例。每个数据库实例都有自己的一组 Firebase Realtime Database 规则,因此您可以精细调整对您的数据的访问权限。

您可以通过 Firebase 控制台或使用 Realtime Database Management REST API 创建和管理数据库实例。

为每个实例修改和部署 Realtime Database 规则

确保您的 Realtime Database 规则允许正常访问项目中的每个数据库实例。每个数据库都有自己的一套规则,您可以通过 Firebase 控制台或者使用 Firebase CLI 部署目标对其进行修改和部署。

  • 如需通过 Firebase 控制台修改和部署规则,请按以下步骤操作:

    1. 转到开发 > 数据库部分的规则标签页。
    2. 选择要修改的数据库,然后对规则进行修改。
  • 若要通过 Firebase CLI 修改和部署规则,请按以下步骤操作:

    1. 修改您数据库实例的规则文件中的规则(例如,foo.rules.json)。
    2. 创建并应用部署目标,以关联使用相同规则文件的数据库。例如:
      firebase target:apply database main my-db-1 my-db-2
      firebase target:apply database other my-other-db-3
    3. 使用部署目标更新 firebase.json 配置文件:

      {
        "database": [
          {"target": "main", "rules": "foo.rules.json"},
          {"target": "other", "rules": "bar.rules.json"}
        ]
      }
      
    4. 运行 deploy 命令:

      firebase deploy

确保始终通过同一工具修改和部署规则。通过 Firebase CLI 部署规则会覆盖您在 Firebase 控制台中所做的修改,而直接在 Firebase 控制台中修改规则会覆盖您近期通过 Firebase CLI 部署的更改。

将您的应用连接到多个数据库实例

使用数据库引用来访问存储在辅助数据库实例中的数据。 您可以根据网址或应用获取对特定数据库实例的引用。如果您不指定网址,则会获得对应用的默认数据库实例的引用。

Web
const app1 = firebase.initializeApp({
  databaseURL: "https://testapp-1234-1.firebaseio.com"
});

const app2 = firebase.initializeApp({
  databaseURL: "https://testapp-1234-2.firebaseio.com"
}, 'app2');

// Get the default database instance for an app1
var database1 = firebase.database();

// Get a database instance for app2
var database2 = firebase.database(app2);
Swift
// Get the default database instance for an app
var ref: DatabaseReference!

ref = Database.database().reference()
// Get a secondary database instance by URL var ref: DatabaseReference! ref = Database.database("https://testapp-1234.firebaseio.com").reference()
Objective-C
// Get the default database instance for an app
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];
// Get a secondary database instance by URL @property (strong, nonatomic) FIRDatabaseReference *ref; self.ref = [[FIRDatabase databaseWithURL:@"https://testapp-1234.firebaseio.com"] reference];

Java

// Get the default database instance for an app
DatabaseReference primary = FirebaseDatabase.getInstance()
        .getReference();

// Get a secondary database instance by URL
DatabaseReference secondary = FirebaseDatabase.getInstance("https://testapp-1234.firebaseio.com")
        .getReference();

Kotlin+KTX

// Get the default database instance for an app
val primary = Firebase.database.reference

// Get a secondary database instance by URL
val secondary = Firebase.database("https://testapp-1234.firebaseio.com").reference

使用 Firebase CLI 时指定实例

使用 --instance 选项指定要应用 Firebase CLI 命令的 Firebase Realtime Database。例如,使用以下命令为名为 my-example-shard.firebaseio.com 的数据库实例运行性能剖析器:

firebase database:profile --instance "my-example-shard"

优化每个数据库上的连接

如果每个客户端都需要在一个会话期间连接到多个数据库,则应仅在必要时连接到各个数据库实例,以减少各个数据库实例的并发连接数。

获取更多建议

将数据分片到多个数据库实例中时,如果您需要更多帮助,请通过我们的 Slack 频道Stack Overflow 与 Firebase 专家联系。