了解firebase中的冲突解决方案

时间:2018-02-16 07:48:39

标签: firebase firebase-realtime-database

我试图了解冲突解决方案在firebase中的工作方式,我需要一些帮助。

假设我的json对象保存在firebase中的一个节点中 实时:

{
    "shape": "rectangle",
    "stroke": 10, 
    "color": "black"
}

我已经定义了一个测试页面,它可以读取这些数据并进行显示,并且还可以实时监听节点上发生的变化。我添加了一项更新数据的规定,最终只更新了特定的密钥值。

示例用例

client 1 - loads the page
    data - {"shape": "rectangle", "stroke": 10, "color": "black"}
client 2 - loads the page 
    data - {"shape": "rectangle", "stroke": 10, "color": "black"}

client 2 goes offline
client 2 updates stroke value to 20 
    data - {"shape": "rectangle", "stroke": 20, "color": "black"}
* data is yet to sync to the server

client 1 makes a change after client 2 has already done with its changes and changes stroke to 5
    data - {"shape": "rectangle", "stroke": 5, "color": "black"}
* data gets synced to the server immediately


client 2 comes online and pushes its changes and overrides the changes made by client 1
    data - {"shape": "rectangle", "stroke": 20, "color": "black"}

理想情况下,由于客户端1在稍后的时间点进行了更改,因此当客户端2数据同步时,应保留客户端1的更改。

如果有人可以建议我在firebase中解决这种类型的冲突(可能是通过定义一些规则和一些额外的逻辑),我会很高兴。

1 个答案:

答案 0 :(得分:7)

使用您当前的代码,预期的行为确实是最后一次写入获胜。

还有两个选择:

  1. 使用事务检测数据是否已更改,然后重试。
  2. 通过使用将写入与每个客户端分开的数据结构来完全防止冲突。
  3. 让我们依次看看每个。

    使用交易是解决此问题的最常见方法。当您在Firebase中使用交易时,客户端会发送"比较并设置"对服务器的操作。这是类型的指令:"如果当前值为A,则将其设置为B"。在您的场景中,这意味着第二次写入检测到笔划已经更改,因此它会重试。

    要了解有关交易的更多信息,请查看Firebase documentation,并在此处回答有关交易的方法。

    这可能听起来像是一个很好的解决方案,但不幸的是它会影响代码的可伸缩性。用户尝试修改相同数据的次数越多,事务就越有可能重试。这就是为什么总是很好地考虑是否可以完全避免冲突。

    防止冲突是最好的解决冲突策略。通过防止冲突,您永远不必解决冲突,这意味着您永远不必编写代码来解决冲突,这意味着您的应用程序将扩展得更好/更远。

    为防止发生冲突,您需要查找用户始终写入唯一位置的数据结构。在您的使用案例中,您可以改为让客户编写他们的"更新操作"而不是让每个客户端更新笔划。到更新队列。例如:

    shapes
      shapeid1
        pushid1: {"shape": "rectangle", "stroke": 10, "color": "black"} /* initial data */
        pushid2: { "stroke": 5 } /* first update */
        pushid3: { "stroke": 20 } /* second update */
    

    在这种数据结构中,没有人会覆盖其他任何人的数据(在安全规则中易于实施的东西)。每个人都只是在形状上添加新的更新(使用ref.push(),按时间顺序生成唯一的位置。)

    要获取形状的当前数据,每个客户端都需要读取该形状的所有更新并在客户端上重新计算它们。对于大多数用例,我已经看到这是一个简单的操作,但如果没有:使用Cloud Function计算状态的周期性快照非常容易。