数据库 频道

摆脱REST的束缚:下一代Web应用为何选择在浏览器中直接运行SQL

  这位厚脸皮的客户正在卷土重来。以下是PGlite和RxDB等下一代本地数据库如何为浏览器带来功能丰富的数据存储。  

  从前,我们有带有简单、不可编程控制台的大型机。所有的权力都集中了。然后,盖茨和乔布斯在每张桌子上都放了一台个人电脑。電力被分配了。然后,互联网出现了,浏览器成为世界上最受欢迎的应用程序。电源回到服务器上,云成为国王。现在,那个钟摆正在向后摆动。

  本文是对本地优先运动的初见,以及将功能丰富的数据存储选项直接嵌入到网络浏览器中的新技术的初见。

  PGLite:浏览器中的数据库

  现代浏览器是多年的密集开发和现实世界测试的结果。今天的浏览器通常在功能强大的机器上运行。然而,像一个踸子一样,每次想要一些数据时,它都必须询问服务器。浏览器状态只是一个暂时的阴影,每次屏幕刷新时都会被消除。加载旋转器、用户界面瀑布、点击和等待;这些都是我们持续依赖后端持久状态的影响。

  但一个替代方案正在出现。想法是直接在浏览器中嵌入一个关系数据库,使用部分数据,并让同步(同步)引擎保持一切一致。瀏覽器與在後臺同步到伺服器的本地資料儲存進行交互。这意味着前端的即时交互性,同时与后端保持对称性。这款下一代浏览器具有更弹性的记录状态,而不仅仅是一个临时缓存。

  出现了几个因素,使浏览器成为一个更强大的数据存储,包括IndexedDB和WebAssembly,为浏览器内NoSQL数据存储PouchDB等工具铺平了道路。但这些天节目的明星可能是PGLite SQL数据库。

  当然,一切都有取而去。将数据库移动到浏览器中具有架构影响。但最重要的变化是逐渐远离网络开发的两个基石:JSON和REST。

  同构未来

  我最近写了一篇关于WinterTC如何推动我们走向同构JavaScript的梦想的文章,其中服务器和客户端完全相同。下一阶段是跨数据存储实现类似的同质性。这最近才随着WASM的成熟而成为可能,WASM在浏览器中运行一个功能齐全的PostgresSQL实例。那个实例,WASM数据库,是PGLite。

  虽然SQLite可以让你在浏览器中接近企业数据库,但PGLite实际上是你在数据中心运行的同一个数据库。它消除了方言的摩擦。WASM运行时(真正是现代编程世界的奇迹)使PGLite成为实际Postgres代码库的轻量级版本。

  所有这些都意味着我们比以往任何时候都更接近一个厚重的客户。当然,有细微差别需要考虑,沿途会有曲折。

  基于形状的同步

  即使API和实现相同,我们也不能在浏览器中创建整个数据库的碎片。它太大了,反正不安全。我们只想要特定用户在给定会话中需要的数据。

  一个有影响力的想法是“基于形状”的同步。这是由ElectricSQL推广的,这也是PGLite背后的力量。形状是像视图一样的东西。它需要一个或多个查询,并使用它们在客户端数据库中填充一段相关数据。只有服务器知道全部真相。客户端订阅服务器中的特定形状(例如,SELECT * FROM issues WHERE assigned_to = 'me')。

  在引擎盖下,同步依赖于Postgres的原生逻辑复制协议。同步引擎是中间件消费者。它监听数据库的提前写入日志(服务器上发生的所有更改的实时流)。当发生与客户端订阅形状相匹配的更改时,引擎会将该特定更新从后台WebSocket推送到浏览器的PGLite实例。这个活动是双向的。本地写入立即应用于用户界面,然后排队并流式返回中央数据库,而引擎则处理必要的冲突解决逻辑。

  在渐进式网络应用程序(PWA)的旧时代,当用户重新上线时,您必须编写命令代码来重播失败的请求。该技术奏效了,但它很脆弱,而且不是很好的开发人员体验。现代同步引擎通过自己完成工作提供了一个更优雅的解决方案。

  此时,你可能会想:“但浏览器是短暂的!用户清除缓存!”

  同步引擎解决了这种自然的反对意见。要了解如何,请思考Git的架构:

  远程数据库(GitHub)是真理的来源。

  本地数据库(您的笔记本电脑)包含工作数据。

  如果用户清除了浏览器缓存,他们并没有丢失数据。他们只是删除了他们的本地存储库。当他们再次登录时,同步引擎基本上执行git clone,将他们的“数据形状”拉回设备。

  无冲突复制数据类型

  但是,如果两个用户在离线时编辑完全相同的数据,会发生什么?在标准数据库中,最后一次写入将覆盖上一个写入。同步逻辑确实需要非常复杂,以处理在形状上操作的众多客户端,并不断将其同步转储到中央数据存储。

  这就是CRDT(无冲突复制数据类型)的用处。

  CRDT是一组深奥的数学结构,具有同步问题的实际应用。这些数据结构(如Map或aList)旨在进行数学合并。这是Git合并冲突(停止工作并需要人工干预)和Google Docs(自动合并每个人的打字)之间的区别。通过使用CRDT逻辑,同步引擎确保用户的离线编辑永远不会丢失;相反,当连接恢复时,它们会无缝组合。

  现在,让我先发制人一下你接下来可能会想什么:这是很多额外的架构。我的意思是,现在我们有两个数据库,一个同步引擎,那个“形状”似乎是服务器上应该存在的SELECT语句的复制。

  从某種意義上说,我們已經把分散式計算,一個典型的難題,在数据存储中拆分了。我们这样做是为了避免加载数据的笨重,但以一个已知的模式为代价:JSON API(和REST)。

  如果我们愿意做这一切,我们一定希望从中获得一些非常有价值的东西,对吗?

  超越JSON API

  这种新方法使网络开发人员20年来一直追求的东西成为可能:桌面级体验。

  通过与本地数据交互,可以在依赖直接网络呼叫时无法触及的用户界面上实现响应能力。拉入一个全面的PostgreSQL实例是一个彻底的解决方案,它避免了像本地缓存这样的半途而废的措施。除此之外,它在开发人员体验中产生了另一个有趣的潜在胜利。

  通过消除后端API,我们摆脱了网络开发人员传统上不得不处理的整层耦合。目标是避免以某种方式手动将客户端数据转换为传输格式,然后返回数据存储格式,然后再返回。(像HTMX这样的框架也在努力实现这一理想,尽管它们的方法不同。)

  在本地优先数据的理想中,我们不必进行任何JSON的马歇。我们只需编写我们想要的SQL语句,同步引擎就会自动处理传输(基于我们定义的规则)。我们不再编写GET /todos端点。相反,我们在组件中编写一个SQL查询:SELECT * FROM todos。

  IndexedDB和OPFS

  虽然PGLite是一项迷人的技术,但它并不是本地优先数据战线上唯一的故事。它实际上是更大的科技星座的一部分。毕竟,开发人员总是能找到存放数据的地方:即本地存储、cookie和IndexedDB。

  IndexedDB是为浏览器提供数据库的真正尝试(事实上,它可以作为支持PGLite实例的快速方法),但它被臭名昭著的笨重的API和性能限制所阻碍。它更像是一个文件系统桶,而不是一个数据库引擎。它不支持复杂的查询、连接或约束。要做任何有趣的事情,你必须自己在JavaScript中编写数据库逻辑,将数据拉入内存进行过滤,这会破坏性能。也就是说,对于现实世界的用例来说,这太混乱了。

  IndexedDB是一个必要的垫脚石,但它不是最终目的地。现代的基础是由WebAssembly和Origin私有文件系统(OPFS)建立的。这些技术让我们停止在JavaScript中重新发明数据库,并开始将成熟的引擎直接移植到客户端中。

  高速文件系统:OPFS

  虽然它听起来像一个晦涩难懂的浏览器规范,但OPFS对现代本地优先架构很重要。WASM提供运行时,OPFS提供文件系统。

  OPFS最终让浏览器能够直接、高性能地访问用户的硬盘。与迫使我们读取/写入整个文件或对象的IndexedDB不同,OPFS允许随机访问写入。这意味着像PGLite这样的数据库可以修改1GB文件中间的4KB小数据页面,而无需重写整个文件。这是缺失的链接,允许服务器级数据库在浏览器中以接近原生性能运行。

  NoSQL替代方案:RxDB

  如果PGLite是“客户端SQL”运动的拥护者,那么RxDB(反应数据库)就是NoSQL等效的。它继承自PouchDB,这是一个在现实世界中使用多年的浏览器内NoSQL数据库。

  PGLite专注于将服务器的结构带给客户端,而RxDB专注于现代用户界面的行为。它是围绕反应性设计的(因此是Rx前缀)。在标准数据库中,您运行查询并获得结果。在RxDB中,您订阅了一个查询:

  //在RxDB中,数据库是状态管理器db.todos.find()。$.订阅(todos => {渲染(todos);});

  当同步引擎从服务器推送新数据时,您的用户界面会立即更新。您不需要像Redux或Pinia这样的状态管理库,因为数据库本身就是反应真理的来源。

  结论

  浏览器不再只是一个文档查看器或简单的终端界面。但新兴的本地优先架构与我们熟悉的REST和类似REST的解决方案截然不同。它带来了它自己的复杂性。

  随着运行时的统一(WinterTC)和工业级本地数据库(PGlite和RxDB)的到来,浏览器有可能成为一个全孔应用程序平台。但它会取代已知的做事方式吗?不是一下子全部,也不是很快。熟悉是编程世界中的巨大压载物。

  本地优先+同步有一天可能会击倒JSON和REST的皇冠。但首先,它必须证明其在现实世界中的可行性。

0
相关文章