关于本地优先有一个令人舒服的误解:挑战在于将数据保存在设备上。它不是。本地保存很简单,任何浏览器都有 IndexedDB,任何手机都有 SQLite。问题总是不同的,这也是美丽的原型与能够承受生产的产品的区别所在。
困难的部分是同步。当写入过程中网络中断时、当两个设备编辑同一条记录时、当用户在三天后重新上线时、当您需要实时而不用每次连接重做整个状态时,请保持本地数据库和服务器数据库的一致性。这就是好心的团队在几个月内陷入困境的沼泽。同步引擎的存在是为了让你不用重新发明这个轮子,它是一个危险的轮子。
同步引擎的真正用途
从本质上讲,同步引擎解决了通常需要手工解决的四个问题。它维护与该用户相关的数据的一致本地副本。它将本地更改可靠地传播到服务器,即使连接在中间中断也是如此。它可以带回远程更改,而您无需编写脆弱的轮询逻辑。它处理两种著作相互竞争时的冲突。
添加到实时交付中,将离线视为正常状态而不是例外,并在长时间断开连接后进行协调。这些项目中的每一项都是一个项目。它们共同构成了软件开发中最边缘的领域之一。同步引擎的价值主张是吸收 API 背后的这种复杂性,就像正常读取和写入数据一样。
实际结果是,您根据本地、同步和即时状态对应用程序进行编程,并且引擎负责与服务器一起跳舞。用户看到一个立即响应的界面,分布式真相在幕后得到认可。这种倒置是[本地优先0体验的核心。
ElectricSQL 和同步 Postgres 的承诺
对于那些已经生活在关系生态系统中的人来说,ElectricSQL 的起点很有吸引力:将 Postgres 的一个子集带到设备上并保持同步。这个想法是,您定义每个客户端感兴趣的行和表(称为形状),并且引擎确保该切片始终在本地更新,并具有离线写入和自动协调功能。
呼吁并不是要抛弃关系模型。您不断思考表、关系和 SQL,然后将同步层置于顶层。对于冲突,该方法历来依赖于底层的 CRDT,这减轻了您手动合并大多数附加案例的负担。对于已经将 Postgres 作为事实来源的团队来说,入门曲线较低。
与之对应的是成熟度和心智模式。随着时间的推移,该项目已经改进了其架构,因此值得准确了解您正在采用的版本和方法。基于形状的部分同步功能强大,但需要仔细设计每个客户端的需求,否则存在带来数据过多或过少的风险。
复制缓存和突变模型
Replicache 押注于不同的理念。它不使用镜像表,而是使用乐观突变模型和本地版本化缓存。您描述突变,它们会在本地即时应用,发送到服务器,并在必要时回滚并在服务器真相到达时重新应用。协调是通过集成到后端的拉推机制来完成的。
最大的优势是控制。 Replicache 不会在服务器上强加特定的数据库,只要您实现同步端点,它就会适合您已有的数据库。这使得它变得灵活且不可知,非常适合那些拥有已建立的后端并且不想更改它的人。乐观的写作体验极佳,模型可预测。
代价是一些工作又回到了你的手中。您设计突变、实现拉取和推送逻辑并决定服务器如何解决冲突,因为这里的业务规则往往比基于 CRDT 的解决方案更加突出。这是更多的集成工作,以换取更少的魔法和更多的行为控制。根据规模,还需要考虑许可和成本方面。
RxDB 和 PowerSync,通往客户的两条路径
RxDB 是 JavaScript 的反应式数据库,它将同步视为离线优先核心之上的插件。您将获得一个具有反应式查询的本地数据库,也就是说,当数据更改时,界面会自行更新,并连接针对不同后端(从 CouchDB 到 GraphQL 和自定义 HTTP 端点)的复制。它很成熟,拥有庞大的社区,并且在网络和混合前端的[离线优先1]应用程序中表现出色。
RxDB 的灵活性也是它的重量。因为它与后端无关,所以大部分复制和冲突解决策略取决于您,并且一些高级功能需要付费许可证。它是一个优秀的客户端工具,但它没有为您提供现成的服务器。
PowerSync 从更具操作性的角度进行攻击,针对那些已经在生产环境中使用 Postgres 的用户。它将 SQLite 放置在设备上,通过逻辑复制监视服务器数据库,并使两者保持同步,并对每个用户接收的数据有明确的规则。其足迹是基础设施产品的足迹,重点是可靠性、[可观察性2]以及对本机移动应用程序的支持,这让需要运营保证而不仅仅是库的团队感到满意。
采用前如何评估
第一个问题不是哪种工具,而是您的数据模型是什么以及您的真相来源在哪里。如果它是关系型 Postgres 并且您不想放弃它,ElectricSQL 和 PowerSync 可以直接与那个世界对话。如果您想要后端不可知论和对突变的精细控制,Replicache 和 RxDB 更有意义。使用错误的工具来对抗你的模型是最常见的遗憾。
第二个问题是关于冲突。回到收敛与修正的区别。在合并本质上是累加的情况下,基于 [CRDT3 ] 的解决方案可以节省精力。如果正确性取决于业务不变量,则更喜欢能够让您对服务器上的分辨率进行显式控制的引擎。最糟糕的选择是向你隐瞒这一决定。
接下来是没有人愿意提前面对的三个因素:锁定、成熟度和成本。询问如果需要的话如何退出该工具,因为同步层往往深深植根于应用程序中。询问该项目稳定了多长时间以及有多少公司正在认真生产而不是演示中运行该项目。并根据实际规模对成本进行建模,计算许可证、服务器基础设施以及每个选项所需的工程时间。
最后,用你最坏的情况而不是你的快乐路径进行诚实的概念验证。模拟三台设备离线编辑、网络不稳定以及几天后重新连接。正是在这个测试中,而不是在教程中,该工具揭示了它是否真正提供了它所承诺的可靠性。
如果您现在正在做出这个决定,请在页面上写下您最敌对的同步场景,并在提交架构之前将其带到每个工具中。正确的引擎是能够度过最糟糕的一天的引擎,而不是具有最佳着陆页的引擎。
另请阅读
- [CRDT:如何同步 Serverless 数据来仲裁冲突4
- [本地优先:首先在您的设备上运行的软件5
- [现实生活中的地方优先:政府、医疗保健和物流6
- [应用后端:架构、技术和最佳实践7
- [离线优先:为没有互联网时进行设计8
- [服务器优先:减轻浏览器负担的架构决策9