互联网级别大变革:本地优先软件!在本地拥有自己的数据,使用CRDT数据结构实现分散式数据合并!


Google Docs和Trello等云应用程序很受欢迎,因为它们可以实现与同事的实时协作,并且使我们可以轻松地从所有设备访问我们的工作。但是,通过在服务器上集中数据存储,云应用程序还会剥夺用户的所有权和代理权。如果服务关闭,则软件将停止运行,并且使用该软件创建的数据将丢失。
在本文中,我们提出了“本地优先软件”软件原则,可以为用户提供协作和所有权。本地优先理念包括跨多个设备脱机工作和协作的能力,同时还提高数据的安全性,隐私性,长期保存和用户控制。
我们调查了现有的数据存储和共享方法,从电子邮件附件到网络应用程序,再到Firebase支持的移动应用程序,我们研究了每种方法的权衡。我们认为:无冲突复制数据类型(CRDT)一开始就是多用户的数据结构,同时也基本上是本地和私有的。CRDT有可能成为实现本地优先软件的基础技术。
我们在几年的时间里,在Ink&Switch开发本地首个软件原型,分享了我们的一些发现。这些实验在实践中测试CRDT的可行性,并探索这种新数据模型的用户界面挑战。最后,我们建议采取一些后续步骤,转向本地第一软件:研究人员,应用程序开发人员以及创业者的创业机会。

(文章比较长,点击标题见原文,这里从CRDT开始)

CRDT作为基础技术
CRDT 于2011年从学术计算机科学研究中脱颖而出。它们是如同哈希Map和列表List一样的通用数据结构,但关于它们的特殊之处在于它们是从头开始的多用户。
每个应用程序都需要一些数据结构来存储其文档状态。例如,如果您的应用程序是文本编辑器,则核心数据结构是组成文档的字符数组。如果您的应用程序是电子表格,则数据结构是包含引用其他单元格的文本,数字或公式的单元格矩阵。如果它是矢量图形应用程序,则数据结构是图形对象的树,例如文本对象,矩形,线条和其他形状。
如果要构建单用户应用程序,则可以使用模型对象,哈希映射,列表,记录/结构等在内存中维护这些数据结构。如果要构建协作式多用户应用程序,则可以将这些数据结构替换为CRDT。
这意味着如果您拥有文档的复制副本,则可以对CRDT进行更改,并且数据结构会跟踪更改。这些更改可以编码为字节字符串,并通过您喜欢的任何通信渠道发送给您的协作者(例如,通过服务器,通过点对点连接,通过本地设备之间的蓝牙,甚至是USB记忆棒)。
您的协作者可以接收这些更改并将其应用于其文档副本。与Git中需要手动解决合并冲突不同的是:CRDT会自动执行合并

特点:

  • 无冲突:当多个协作者进行更改时,它们可以自动合并到一致的文档视图中;
  • 复制:每个协作者都有自己的数据副本,存储在本地设备上;
  • 数据类型:通用数据结构,如地图和列表。

这些属性直接映射到我们的本地优先理想。在本地拥有数据副本而不是依赖于服务器,可实现脱机工作,长寿,良好性能和用户控制。能够自动合并更改可实现多设备使用和协作。通信信道的灵活性允许加密,从而提高隐私和安全性。
CRDT跟踪的更改可以像单个按键一样小,从而实现Google Docs风格的实时协作。但您也可以收集更多更改并将其作为批处理发送给协作者,更像是Git中的pull请求。由于数据结构是通用的,我们可以开发用于存储,通信和管理CRDT的通用工具,从而使我们不必在每个应用程序中重新实现这些功能。

有关CRDT的更多技术介绍,我们建议:


Ink&Switch开发了一种名为Automerge的开源JavaScript CRDT实现。它基于我们之前对JSON CRDT的研究。然后我们将Automerge与Dat网络堆栈结合起来形成Hypermerge。我们并不认为这些图书馆完全实现了本地优先理想 - 仍然需要做更多的工作。
但是,根据我们的经验,我们相信CRDT有可能成为新一代软件的基础。正如分组交换是互联网和网络的支持技术一样,或者电容式触摸屏是智能手机的支持技术,因此我们认为CRDT可能是协作软件的基础,可为用户提供对其数据的完全所有权。

Ink & Switch的原型
虽然学术研究在设计CRDT算法和验证其理论正确性方面取得了很好的进展,但迄今为止这些技术的工业应用相对较少。此外,大多数工业CRDT一直用于以服务器为中心的计算,但我们相信这项技术在创造性工作的客户端应用程序中具有巨大潜力。

使用CRDT的以服务器为中心的系统包括Azure Cosmos DBRiakWeave MeshSoundCloud的RoshiFacebook的OpenR。但是,我们最感兴趣的是在最终用户设备上使用CRDT。

这是我们实验室开发一系列实验原型的动机,这些原型具有基于CRDT构建的协作式本地优先应用程序。每个原型都提供了最终用户体验,模仿现有的创意工作应用程序,如Trello,Figma或Milanote。
这些实验探讨了三个方面的问题:

  • 技术可行性。CRDT与工作软件有多接近?我们需要什么才能开始网络通信或安装软件?
  • 用户体验。本地优先软件如何使用?如果没有权威的集中式服务器,我们能否获得无缝的Google Docs实时协作体验?对于除源代码之外的数据类型,Git,离线友好,异步协作体验如何?一般来说,没有集中式服务器,用户界面如何变化?
  • 开发经验。对于应用程序开发人员,如何使用基于CRDT的数据层与现有存储层(如SQL数据库,文件系统或核心数据)进行比较?分布式系统难以编写软件吗?我们需要模式和类型检查吗?开发人员将使用什么来调试和内省应用程序的数据层?

我们使用Electron,JavaScript和React构建了三个原型。这为我们提供了Web技术的快速开发能力,同时也为我们的用户提供了他们可以下载和安装的软件,我们发现这是本地第一感觉的重要组成部分。

1. Trellis是一款以流行的Trello项目管理软件为蓝本的看板
2. PixelPusher是一个协作绘图程序,为Javier ValenciaPixel Art带来了类似Figma的实时体验。
3. PushPin是一个类似于MiroMilanote的混合媒体画布工作区。作为我们构建在Automerge上的第三个项目,它是这三个中最完全实现的。我们的团队和外部测试用户的真实使用给底层数据层带来了更大的压力。

经验教训
我们从构建和使用这些原型中学到了以下经验教训。
1.CRDT技术是有效的。
从一开始我们就对Automerge的可靠性感到惊喜。我们团队中的应用程序开发人员能够相对轻松地集成库,并且数据的自动合并几乎总是简单而无缝。

2.离线工作的用户体验非常出色。
脱机,继续工作的过程只要你想要,然后重新连接以便与同事合并更改效果很好。

3. 与功能反应编程(FRP)结合使用时,开发人员的经验是可行的。
React的FRP模型非常适合CRDT。基于CRDT的数据层意味着用户的文档同时从本地用户获得更新(例如,当他们键入文本文档时),但也来自网络(当其他用户和其他设备对文档进行更改时)。
由于FRP模型可靠地将应用程序的可见状态与共享文档的基础状态同步,因此开发人员可以免除跟踪来自其他用户的更改并将其与当前视图进行协调的繁琐工作。此外,通过确保通过单个函数(“reducer”)对基础状态进行所有更改,可以轻松确保将所有相关的本地更改发送给其他用户。
这个模型的结果是我们所有的原型都可以通过应用程序开发人员轻松实现实时协作和完全脱机功能。这是一个重要的好处,因为它允许应用程序开发人员专注于他们的应用程序而不是数据分发的挑战。

4. 冲突并不像我们担心的那样严重。
我们很好奇用户在与他人合作时遇到工作冲突的频率。我们惊喜地发现,用户具有直观的人与人之间的协作感,并避免与他们的协作者产生冲突。在确实发生冲突的情况下,无论如何解决和满足冲突往往是任意的。例如,如果两个用户在文档标题中修正了拼写错误,他们可能不会以相同的方式执行此操作,但他们通常不关心选择哪个结果。
当不同的用户同时修改文档状态的不同部分时,Automerge将毫不费力地合并这些更改。例如,使用看板应用程序,一个用户可以在卡片上发布评论,另一个用户可以将其移动到另一个列,合并的结果将反映这两个变化。
如果冲突解决不明确,Automerge会保留冲突的值并允许应用程序解决它们。在PixelPusher原型中,我们探索了用于解决冲突的用户界面。将这些特征与变更历史检查相结合是一个开放的研究问题。

5. 可视化文档历史记录非常重要。
在分布式协作系统中,其他用户可以随时向您提供任意数量的更改。与服务器调解变更的集中式系统不同,本地优先应用程序需要找到自己的解决方案来解决这些问题。如果没有合适的工具,就很难理解文档的工作方式,文档的版本或贡献的来源。
在Trellis项目中,我们尝试了“时间旅行”界面,允许用户及时移回以查看合并文档的早期状态,并在从其他用户收到更改时自动突出显示最近更改的元素。以线性方式遍历可能复杂的合并文档历史记录的能力有助于提供上下文,并且可以成为理解协作的通用工具。

6.URL是一种很好的共享机制。
我们尝试了许多与其他用户共享文档的机制,并发现受Web启发的URL模型对用户和开发人员最有意义。可以复制和粘贴URL,并通过电子邮件或聊天等通信渠道进行共享。超出秘密URL的文档的访问权限仍然是一个开放的研究问题。

7.点对点系统永远不会完全“在线”或“离线”,并且很难推断数据如何在其中移动。
传统的集中式系统通常是“向上”或“向下”,由每个客户端通过其维持与服务器的稳定网络连接的能力来定义的状态。服务器确定给定数据的真实性。
在分散的系统中,我们的数据可能具有千变万化的复杂性。任何用户可能对他们拥有的数据,选择共享或接受的数据有不同的看法。例如,一个用户对文档的编辑可能在飞机上的笔记本电脑上; 当飞机降落并且计算机重新连接时,这些更改将分发给其他用户。其他用户可能会选择接受对其文档版本的全部,部分或全部更改。
文档的不同版本可能会导致混淆。与Git存储库一样,特定用户在“主”分支中看到的内容是他们上次与其他用户通信时的功能。新到的更改可能会意外地修改您正在处理的文档的某些部分,但手动合并每个用户的每个更改都很繁琐。分散文档使用户能够控制自己的数据,但需要进一步研究,以了解这在实际用户界面术语中意味着什么。

8.CRDT累积了大量的更改历史记录,从而产生了性能问题。
我们的团队将PushPin用于“真实”文档,例如sprint规划。性能和内存/磁盘使用很快成为一个问题,因为CRDT存储所有历史记录,包括逐个字符的文本编辑。这些堆积起来,但不容易被截断,因为无法知道有人可能在六个月之后重新连接到您的共享文档并且需要合并从那一点开始的更改。
我们继续优化Automerge,但这是正在进行的工作的一个主要领域。

9.网络通信仍然是一个未解决的问题。
CRDT算法仅提供数据合并,但并没有说明不同用户的编辑是如何到达同一物理计算机。
在这些实验中,我们尝试通过WebRTC进行网络通信; 使用Dropbox和USB密钥复制文件的“sneakernet”实现; 可能使用IPFS协议 ; 并最终选择了DatHypercore点对点库。
CRDT不需要对等网络层; 使用服务器进行通信对CRDT来说很好。但是,为了充分实现本地优先软件的长寿目标,我们希望应用程序能够超过其供应商管理的任何后端服务,因此分散式解决方案是合乎逻辑的最终目标。
在我们的原型中使用P2P技术产生了不同的结果。一方面,这些技术还远未达到生产准备阶段:特别是NAT遍历不可靠,具体取决于用户当前连接的特定路由器或网络拓扑。但P2P协议和分散式网络社区所建议的承诺是巨大的。在没有互联网访问的计算机之间进行实时协作在依赖集中式API的世界中感觉像魔术一样。

10.云服务器仍然可以用于发现,备份和突发计算。
像PushPin这样的实时协作原型允许用户在没有中间服务器的情况下与其他用户共享他们的文档。这非常适合隐私和所有权,但可能会导致用户共享文档,然后在其他用户连接之前关闭笔记本电脑盖。如果用户不在同一时间,则无法相互连接。
因此,服务器可以在本地第一世界中发挥作用 - 不是作为中央机构,而是作为支持客户端应用程序而不是关键路径的“云对等体”。例如,存储文档副本并在其上线时将其转发给其他对等方的云对等方可以解决上面关闭的笔记本电脑问题。
HashbaseDat and Beaker Browser的云对等和桥接的示例。

同样,云同行可能是:

  • 档案/备份位置(特别是对于存储有限的电话或其他设备);
  • 传统服务器API的桥梁(例如天气预报或股票行情);
  • 突发计算资源的提供者(如使用强大的GPU渲染视频)。

传统系统与本地优先系统之间的关键区别不在于缺少服务器,而在于其职责的变化:它们是支持角色,而不是真相的唯一来源。

结论
计算机是人类有史以来最重要的创作工具之一。软件已成为我们完成工作的渠道和工作所在的存储库。
为了追求更好的工具,我们将许多应用程序迁移到云端。云计算软件在很多方面都优于“老式”软件:它提供了可在世界任何地方访问的协作式,始终最新的应用程序。我们不再担心我们正在运行的软件版本,或者文件所在的机器。
但是,在云中,数据的所有权属于服务器,而不是用户,因此我们成为了自己数据的借用者。在云应用程序中创建的文档注定会在这些服务的创建者停止维护时消失。云服务无法长期保存。没有Wayback Machine可以恢复落伍的Web应用程序。互联网档案馆无法保留您的Google文档。
在本文中,我们探索了未来软件的新方法。我们已经证明,用户可以保留对数据的所有权和控制权,同时还可以从与云相关的功能中受益:无缝协作和从任何地方访问。它可以充分利用这两个世界。
但是,在实践中需要做更多的工作来实现本地优先的方法。应用程序开发人员可以采取渐进的步骤,例如改进脱机支持并更好地利用设备上的存储。研究人员可以继续改进本地优先软件的算法,编程模型和用户界面。企业家可以将CRDT和点对点网络等基础技术开发成能够为下一代应用提供动力的成熟产品。
今天,很容易创建一个Web应用程序,其中服务器获取所有数据的所有权。但是,构建尊重用户所有权和代理权的协作软件太难了。为了改变平衡,我们需要改进开发本地优先软件的工具。