现在,越来越多的新产品旨在对全球产生影响,用户体验正在迅速成为决定它们成败的关键因素。应用程序的这些属性会显著影响用户体验
- 性能与低延迟
- 应用程序按预期运行
- 安全性
- 功能和UI
让我们开始通往完美用户体验的征程吧!
1) 性能与低延迟
其他人之前也说过;性能就是用户体验(1,2)。当你吸引了潜在访客的注意力时,延迟的轻微增加可能会让你再次失去这种注意力。
2) 应用程序按预期运行
“按预期运行”到底是什么意思?这意味着如果我在应用程序中将我的姓名更改为“Robert”,然后重新加载应用程序,我的姓名将是Robert而不是Brecht。应用程序提供这些保证似乎很重要,对吧?
应用程序能否兑现这些保证取决于数据库。在追求低延迟和高性能时,我们最终会进入分布式数据库领域,其中只有少数较新的数据库提供了这些保证。在分布式数据库领域,可能存在风险,除非我们选择强一致性(而不是最终一致性)数据库。在本系列文章中,我们将详细介绍这意味着什么,哪些数据库提供了这种称为强一致性的功能,以及它如何帮助您轻松构建超快的应用程序。
3) 安全性
安全性似乎并不总是会立即影响用户体验。但是,一旦用户注意到安全漏洞,关系就可能受到无法挽回的损害。
4) 功能和UI
令人印象深刻的功能和出色的UI对意识和潜意识都有很大的影响。通常,人们只有在体验了产品的视觉和感受后才会想要特定的产品。
如果数据库节省了设置和配置时间,那么我们其余的精力就可以集中在提供令人印象深刻的功能和出色的UI上。好消息是,如今,有一些数据库可以满足上述所有要求,无需配置或服务器配置,并提供易于使用的API(如开箱即用的GraphQL)。
这种新型数据库有什么不同之处?让我们退一步,看看对更低延迟和更好用户体验的持续追求,以及数据库研究的进步,最终如何导致了一种新型数据库的出现,这些数据库是现代应用程序的理想构建块。
分布式探索
一、内容分发网络
如前所述,性能对用户体验有重大影响。有几种方法可以提高延迟,最明显的方法是优化应用程序代码。一旦应用程序代码得到充分优化,网络延迟和数据库的读写性能通常仍然是瓶颈。为了满足我们的低延迟要求,我们需要确保我们的数据尽可能靠近客户端,方法是将数据全球分布。我们可以通过让多台机器协同工作来实现第二个要求(读写性能),或者换句话说,复制数据。
分布式带来更好的性能,从而带来良好的用户体验。我们已经看到了广泛使用一种分布式解决方案来加速静态数据的交付;它被称为内容分发网络 (CDN)。CDN 被 Jamstack 社区高度重视,以减少其应用程序的延迟。他们通常使用 Next.js/Now、Gatsby 和 Netlify 等框架和工具将前端 React/Angular/Vue 代码预先组装成静态网站,以便他们可以从 CDN 提供服务。

不幸的是,CDN 并非适用于所有用例,因为我们不能依赖于静态生成的 HTML 页面来处理所有应用程序。有许多类型的极具动态性的应用程序,您无法静态生成所有内容。例如
- 需要实时更新以实现用户之间即时通信的应用程序(例如,聊天应用程序、协作绘图或写作、游戏)。
- 通过过滤、聚合、排序以及以多种方式操作数据来以多种不同形式呈现数据的应用程序,您无法预先生成所有内容。
二、分布式数据库
通常,高度动态的应用程序将需要分布式数据库来提高性能。与 CDN 一样,分布式数据库也旨在成为一个全球网络,而不是单个节点。从本质上讲,我们希望从具有单个数据库节点的场景…

…转变为数据库成为网络的场景。当用户从特定的大陆连接时,他将自动重定向到最近的数据库。这将导致更低的延迟和更快乐的最终用户。

如果数据库是通过电话等待的员工,则数据库员工会通知您附近有员工,并将电话转接过去。幸运的是,分布式数据库会自动将我们路由到最近的数据库员工,因此我们无需再麻烦另一个大陆的数据库员工。

分布式数据库是多区域的,您始终会被重定向到最近的节点。
除了延迟之外,分布式数据库还提供了第二个和第三个优势。第二个是冗余,这意味着如果网络中的某个数据库位置被哥斯拉袭击完全摧毁,您的数据也不会丢失,因为其他节点仍然具有您数据的副本。


最后但并非最不重要的是,使用分布式数据库的第三个优势是扩展。在一个服务器上运行的数据库很快就会成为应用程序的瓶颈。相反,分布式数据库在多台服务器上复制数据,并且可以根据应用程序的需求自动扩展和缩减。在一些高级分布式数据库中,这方面完全由您自己处理。这些数据库被称为“无服务器”,这意味着您甚至不必配置数据库何时应该扩展和缩减,并且您只需为应用程序的使用付费,仅此而已。
分发动态数据将我们带入分布式数据库的领域。如前所述,这里可能存在一些挑战。与 CDN 不同,数据是高度动态的;数据可以快速更改,并且可以进行过滤和排序,这带来了额外的复杂性。数据库领域探索了不同的方法来实现这一点。早期的方案不得不做出牺牲才能达到所需的性能和可扩展性。让我们看看分布式方案是如何演变的。

传统数据库的分布式方案
一个合乎逻辑的选择是建立在传统数据库(MySQL、PostgreSQL、SQL Server)的基础上,因为已经投入了大量的精力在它们上面。然而,传统数据库并非为分布式而构建,因此采用了相当简单的分布式方法。扩展读取的典型方法是使用读取副本。读取副本只是数据的副本,您可以从中读取但不能写入。这样的副本(或复制)将查询从包含原始数据的节点卸载。这种机制非常简单,数据会随着输入逐渐复制到副本中。
由于这种相对简单的方法,副本的数据始终比原始数据旧。如果您在特定时间点从副本节点读取数据,您可能获得的值比从主节点读取的值要旧。这称为“陈旧读取”。使用传统数据库的程序员必须意识到这种可能性,并考虑到此限制进行编程。还记得我们一开始给出的例子,我们写入一个值并重新读取它吗?在使用传统数据库副本时,您不能期望读取您写入的内容。
您可以通过在所有副本都感知到写入之前,在前端乐观地应用写入结果来稍微改善用户体验。但是,如果更新尚未到达副本,则网页的重新加载可能会将 UI 返回到先前状态。然后用户会认为他的更改从未保存。

第一代分布式数据库
在传统数据库的复制方法中,明显的瓶颈是所有写入都发送到同一个节点。机器可以进行纵向扩展,但最终会遇到瓶颈。随着应用程序的普及和写入量的增加,数据库将不再能够快速地接收新数据。为了在读取和写入方面进行横向扩展,分布式数据库应运而生。分布式数据库也保存数据的多个副本,但您可以写入这些副本中的每一个。由于您通过每个节点更新数据,因此所有节点都必须相互通信并相互告知新数据。换句话说,它不再像传统系统那样是单向的了。

然而,这些类型的数据库仍然可能遭受前面提到的陈旧读取的影响,并引入许多其他与写入相关的潜在问题。它们是否会受到这些问题的影响取决于它们在可用性和一致性方面做出的决定。
第一代分布式数据库通常被称为“NoSQL 运动”,这个名称受 MongoDB 和 Neo4j 等数据库的影响,它们也提供了 SQL 的替代语言和不同的建模策略(文档或图形而不是表格)。NoSQL 数据库通常没有传统的数据库特性,例如约束和连接。随着时间的推移,这个名称似乎成为了一个糟糕的名称,因为许多被认为是 NoSQL 的数据库确实提供了某种形式的 SQL。出现了多种解释,声称 NoSQL 数据库
- 不提供 SQL 作为查询语言。
- 不仅提供 SQL(NoSQL = Not Only SQL)
- 不提供传统的特性,例如连接、约束、ACID 保证。
- 以不同的方式建模其数据(图、文档或时间模型)
一些较新的非关系型但提供 SQL 的数据库随后被称为“NewSQL”,以避免混淆。
对 CAP 定理的错误解读
第一代数据库受到 CAP 定理的强烈启发,该定理规定在网络分区期间,您无法同时拥有数据一致性和可用性。网络分区本质上是发生某些事情导致两个节点无法再相互通信新数据的情况,并且可能由于多种原因而出现(例如,据报道鲨鱼有时会啃食谷歌的电缆)。一致性意味着数据库中的数据始终正确,但不一定对您的应用程序可用。可用性意味着您的数据库始终在线,并且您的应用程序始终能够访问该数据,但不保证数据正确或在多个节点中相同。我们通常谈论的是高可用性,因为不存在 100% 的可用性。可用性以 9 的倍数表示(例如 99.9999% 的可用性),因为始终存在一系列事件导致停机时间的可能性。

但是如果没有网络分区会发生什么?数据库供应商对 CAP 定理的理解过于广泛,要么选择接受潜在的数据丢失,要么选择保持可用,无论是否存在网络分区。虽然 CAP 定理是一个良好的开端,但它没有强调的是,在没有网络分区的情况下,可以实现高可用性和一致性。大多数时候,不存在网络分区,因此通过将 CAP 定理扩展到 PACELC 定理来描述这种情况是有意义的。关键的区别在于最后三个字母(ELC),它们代表 Else Latency Consistency(否则延迟一致性)。该定理规定,如果没有网络分区,数据库必须在延迟和一致性之间取得平衡。

简单来说:当没有网络分区时,当一致性保证提高时,延迟也会增加。但是,我们会看到现实情况比这还要微妙。
这与用户体验有什么关系?
让我们看一个放弃一致性如何影响用户体验的例子。考虑一个应用程序,它为您提供了一个友好的界面来组成人员团队;您可以将人员拖放到不同的团队中。

将某人拖放到某个团队后,将触发更新以更新该团队。如果数据库不保证您的应用程序能够立即读取此更新的结果,则 UI 必须乐观地应用这些更改。在这种情况下,可能会发生不好的事情:
- 用户刷新页面,不再看到他的更新,并认为他的更新消失了。当他再次刷新时,它突然又回来了。
- 由于与另一个更新发生冲突,数据库未成功存储更新。在这种情况下,更新可能会被取消,用户永远不会知道。他可能只会在下次重新加载时注意到他的更改消失了。
这种一致性和延迟之间的权衡引发了前端和后端开发人员之间许多激烈的讨论。第一组希望获得出色的 UX,用户在执行操作时会收到反馈,并且可以 100% 确定一旦他们收到此反馈并对其做出响应,其操作的结果就会一致地保存。第二组希望构建一个可扩展且性能良好的后端,并且认为除了牺牲前面提到的 UX 要求来实现这一点之外别无选择。
两组都有合理的观点,但没有万能的解决方案可以同时满足两者。当事务增加并且数据库成为瓶颈时,他们唯一的选择是使用传统数据库复制或分布式数据库,后者牺牲了强一致性以换取所谓的“最终一致性”。在最终一致性中,对数据库的更新最终将应用于所有机器,但不能保证下一个事务能够读取更新的值。换句话说,如果我将我的名字更新为“Robert”,那么如果我在更新后立即查询我的名字,我实际上是否会收到“Robert”并无保证。
一致性成本
为了处理最终一致性,开发人员需要意识到这种数据库的局限性,并做很多额外的工作。程序员经常求助于用户体验技巧来隐藏数据库的局限性,而后端则必须编写大量额外的代码层来适应各种故障场景。围绕这些局限性寻找和构建创造性的解决方案深刻地影响了前端和后端开发人员的工作方式,显著增加了技术复杂性,同时仍然无法提供理想的用户体验。
我们可以将确保数据正确性所需的这些额外工作视为应用程序开发人员必须为提供良好的用户体验而支付的“税”。这是使用在当今网络规模并发环境中无法提供一致性保证的软件系统的税。我们称之为一致性税。
值得庆幸的是,新一代数据库已经发展起来,它不需要您支付一致性税,并且可以在不牺牲一致性的前提下进行扩展!
第二代分布式数据库
第二代分布式数据库已经出现,以提供强一致性(而不是最终一致性)。这些数据库可以很好地扩展,不会丢失数据,也不会返回陈旧的数据。换句话说,它们按照您的预期执行,并且不再需要了解其局限性或支付一致性税。如果您更新了一个值,那么下次读取该值时,它始终反映更新后的值,并且不同的更新按其写入的相同时间顺序应用。FaunaDB、Spanner和FoundationDB是目前唯一提供无限制强一致性的数据库(也称为严格串行化)。
PACELC 定理再探

第二代分布式数据库已经实现了以前被认为不可能的事情;它们偏向于一致性,并且仍然提供低延迟。这得益于智能同步机制,例如Calvin、Spanner和Percolator,我们将在本系列文章的第 4 部分中详细讨论这些机制。虽然旧的数据库仍然难以在较低的延迟下提供高一致性保证,但基于这些新的智能算法构建的数据库则没有此类限制。
数据库设计极大地影响了高一致性下可达到的延迟。
由于这些新算法允许数据库同时提供强一致性和低延迟,因此通常没有充分的理由放弃一致性(至少在没有网络分区的情况下)。您这样做的情况仅限于极低的写入延迟是唯一真正重要的事情,并且您愿意为了实现它而丢失数据。

这些数据库是否仍然是 NoSQL 数据库?
对这一新一代分布式数据库进行分类不再是件简单的事。仍然有很多努力(1、2)来解释 NoSQL 的含义,但由于 NoSQL 和 SQL 数据库正在彼此靠近,因此它们都不再完全有意义。新的分布式数据库借鉴了不同的数据模型(文档、图、关系、时间序列),其中一些数据库提供了ACID保证,甚至支持 SQL。它们与 NoSQL 仍然有一点共同点:它们是为了解决传统数据库的局限性而构建的。一个词永远无法描述数据库的行为方式。将来,通过回答以下问题来描述分布式数据库将更有意义
- 它是否具有强一致性?
- 分布式是否依赖于读取副本,或者它是真正的分布式?
- 它借鉴了哪些数据模型?
- 查询语言的表达能力如何,以及它的局限性是什么?
结论
我们解释了应用程序如何能够从新一代全球分布式数据库中获益,这些数据库可以以类似 CDN 的方式从最近的位置提供动态数据。我们简要回顾了分布式数据库的历史,并发现它并非一帆风顺。许多第一代数据库被开发出来,它们的一致性选择(主要受 CAP 定理驱动)要求我们编写更多代码,同时仍然降低了用户体验。直到最近,数据库社区才开发出允许分布式数据库将低延迟与强一致性相结合的算法。一个新时代已经到来,一个我们不再需要在数据访问和一致性之间做出权衡的时代!
在这一点上,您可能希望看到最终一致性数据库潜在陷阱的具体示例。在本系列的下一篇文章中,我们将介绍这一点。敬请期待这些即将发布的文章
非常有见地!迫不及待地想阅读其余的文章!
嘿,Gust,感谢你的反馈!我们很高兴你喜欢它。
帖子将每周发布,因此下一篇文章应该在 3 月 12 日发布。
如果您有任何反馈或想法,请在 Twitter 上告诉我们(标签 @fauna)/ Slack(http://community.fauna.com/)