简介
数据库是计算中最有用和最基础的结构之一。 它们使我们能够将呈指数级增长的信息量,按照信息架构的高效、逻辑模式来组织它。任何时候,任何信息都需要在任何长度的时间内被保存,它由数据库保存,从一张纸上简单的杂货清单,到数十亿条错综复杂、相互关联的记录,这些记录被组织在一个数据库结构中,需要对其用户(无论是一个还是数百万个)做出高度响应。
一个数据库的 状态是它在任意时间段的一个快照。状态可以通过以下方式改变 事件:每次有事件发生改变数据库时,快照就会变形为新的状态。 例如,如果你向我们的购物清单添加一个项目,这就是一个事件。 同样,如果你把一件杂货放到你的篮子里,并把它从你的清单上划掉,你就改变了清单的状态(同时也改变了你对该物品的思想状态,从不用考虑它的意义上说)。
事件驱动架构是一个计算概念,专门处理事件如何影响信息的范式。 它是一种对我们所拥有的信息进行处理的方式,在这种情况下,具体来说,就是对信息所处的任何状态可以采取的行动。 例如,如果绿灯亮了,我们会尽快对这一信息做出反应,并假设十字路口的交通已经完全清空,我们就继续前进。 绿灯的出现 事件触发了一个行动,将我们的 状态从静止到移动。
实时的概念是指不只是对事件做出反应的能力,而且是即时的,或者说就人类的感知而言,实际上是即时的。消费者越来越需要(在感知上)即时性的体验,而 "尽可能快,但不能更快 "的服务水平协议已经不能满足要求。为了满足这些要求,实时性的最后期限要严格得多。
一些开发者使用数据库是因为他们的用例有写、存储和检索数据的要求。其他开发者使用实时,因为他们有来自用户的交互式的、实时的需求,在很短的期限过后,数据就会失去所有或大部分的商业价值。有些开发者仍然对两者都有强烈的需求,为了尽快推出最小可行的产品,他们选择了低风险的一体化解决方案,而这些解决方案恰好包括一些实时功能。
没有一个问题是规模化的
如果你把你的问题分成一系列的块,在开发周期的早期有一个巨大的 "适合所有盒子 "的解决方案是很好的,因为它意味着你可以快速开始,并知道你要去哪里。假设你使用一个BaaS,因为它有这么多的功能,而其中的一个功能被宣传为实时的。
在开发周期的早期,既能做一些数据库的事情又能做一些实时的事情的通用解决方案是很好的。 如果你从来没有到过一个超越你的平台产品的阶段,那么你的应用和你的服务紧密结合起来可能就足够了。
一些结合数据库和实时产品的软件的例子包括Firestore、Firebase和Supabase。 它们在原型设计阶段有很多价值可言。
只要你走出那个用于简单的移动和网络应用的BaaS的基本范式--特别是简单的应用,因为大多数应用不需要非常大量的状态、复杂的数据库,或者将一些数据连接在一个容易进出的地方--只要你走出那个范式,那么这就不再是一件简单的事情。 紧密耦合/缺乏模块化在严重的企业规模上会产生压力和崩溃。
当你的应用程序开始变得非常快或达到非常大的数字时,简单的部分就会消失,因为在规模上没有问题是简单的。 即使是像Postgres这样的严重规模的数据库解决方案--能够处理每秒数千次的并发写入--在试图以实时的方式使用它们时也会陷入困境。
关于模块化
主要问题是缺乏模块化:每个工具都应该做自己的工作。 数据库是数据的基础。 它们应该做一件事,而且是一件好事,那就是成为真理和数据的一个基本来源。它们不应该为实时问题所累--这不是它们的设计优势。 他们应该做存储,而另一个专门的部门应该做实时通信。所有其他的问题都源于此。

系统内耦合和内聚的最佳实践:每个模块内的内聚应该是高的;模块间的耦合应该是低的。
在规模上,特别是在企业层面上,万物一体的解决方案的紧密耦合会使复杂性膨胀,并开始分解/暴露出早期阶段的互连性是多么的薄弱。 例如,如果你能接受并非所有的读数都有最新的状态,那么扩大规模就更容易了,因为你不必在每次读取某些数据时检查最新的状态。你的实例越多,检查的成本就越高。 但如果你想保证所有地方的状态都是同步的,那么在规模上就会出现问题。
正确的工具适用于正确的工作
如果这适合你的业务需求,选择一个多合一的解决方案是非常有意义的。 你希望通过在正确的时间为正确的工作选择正确的工具,使运营成本最小化,竞争优势最大化。
然而,其中一些功能经常是附加的,或者不是最好的品种。 有一个熟悉的陷阱,就是试图从每一个可用的功能中榨取一切。 然而,最实用的方法是选择一个关键的功能子集--认证、存储、托管、实时功能、云功能等--然后根据你的业务需求对它们进行评估,对于缺失的部分,以模块化的方式添加最佳品种。
评估实时数据库时要问的问题
根据定义,在规模上,你必须考虑模块化--没有一个工具可以做所有的事情;每个工具都应该独立地做好一件事--你应该尽可能努力地把你的实时问题与你的存储问题解耦。
在对任何要求存储和实时性的解决方案进行评估的过程中,都应该提出大量的问题。
以下是评估实时数据库时需要考虑的注意事项的非详尽列表。
性能
你的平台会自动缩放你的数据库吗?它是如何经受住严重的负载或快速上升的所述负载的?带宽、CPU、内存和磁盘的使用能否经受住高峰,特别是非常突然的高峰,同时保持可接受的延迟?你是否依赖云功能来实现 瞬时结果或者你只是为长期运行的任务部署它们?在 有多少个并发连接的时候,性能会发生变化吗? 你是否需要将你的表同步到可能有也可能没有内存的小设备上?你的平台所提供的声称的可用性是否如宣传的那样可用?它是否能随着你的使用情况而弹性地扩展?你是否需要在预期的流量高峰前人为地启动?
操作
该平台的限制是什么?集成是同类中最好的吗?这是一个你能成功的架构吗?让所有的组件同时绑定在一个平台上,这种风险是否可以接受?有什么样的保障措施来防止意外的超额使用? 你能支付你的方式来摆脱瓶颈吗?
数据库功能
你需要复杂的数据库结构吗? 该数据库是否符合ACID标准(原子性、一致性、隔离性和持久性)? 它是否包括一个 全功能的查询语言, 触发器、外键或存储过程?你现在需要哪些东西?(一般来说,数据库应该有其中的大部分,而单独的实时系统应该专门用于实时关注。)是否有一个模块化的方法来增加功能? 你的数据架构是否可以扩展? 你是否需要考虑本地存储和本地处理的影响?
实时性特点
你的需求是否包括实时功能,如 有保证的、几乎是即时的、有秩序的交付? idempotency,或规模化的存在如何? 它们是如何定义的,它们是否有界限? 你的潜在平台提出的解决方案是什么? 它是一个简单的实现吗? 它是模块化的吗? 你的架构是事件驱动的吗?它是否可以通过每一种类型的事件的主题来弹性地扩展? 你是否被迫设计自己的负载平衡,以应对超出规定限制的大规模扇形扩张?你能在没有数据库事务的情况下进行实时更新吗?你是使用HTTP还是WebSockets? 什么类型的 交付承诺你能给你的用户什么?你需要一个具有一些实时能力的BaaS服务,还是一个具有可扩展的实时组件与之松散耦合的高性能数据库解决方案?
状态
状态同步是很难实现的,很多答案都是 "这取决于"。**最新的状态是你所关心的全部吗?**你必须在设备之间同步大量的数据,还是你只是与服务器共享状态?基于事件的触发器是否足够了?你是否有能力调整你的状态的同步方式和时间? 平台是否已经弄清了 同步化的硬确定性收敛问题通过事件?是否有 分布式状态/事件的基元?
归根结底,所有这些问题只归结为一个。
"什么是正确的工具,在正确的时间用于正确的工作?"
大规模扩展以数据库为中心的应用程序时的典型开发路径
当你的应用程序严重扩展时,你可以采取几种开发路径,但最终的结果总是以高内聚力和松耦合为特征的解决方案。
例如,你的应用程序一开始就采用BaaS,因为存在对认证、存储和云计算等全套后端功能的需求。你在你的应用中增加了实时功能,以至于它变得难以扩展,而且直接使用数据库对某一事物进行实时更新,使用户感觉到动态,其复杂性太大。
在这种情况下,最好的办法是将实时性方面的工作抽象出来,交给专业的供应商来做触发器和其他事件。 你仍然使用原来的数据库来处理数据,也许还可以用来处理BaaS所带来的其他好处。
或者,你从一个数据库开始,但发现你的需求增加到对数据的更复杂的操作。 你从同一个供应商那里转到更强大的结构化解决方案,和/或转到Cassandra、Postgres、DynamoDB或同等的解决方案。 随着规模的扩大,实时组件仍然缺乏,在这一点上,增加一个实时更新系统是有意义的,该系统可以与任何其他系统很好地配对,超越数据库的限制。
现实世界的例子
描述这个瓶颈的一个方法是使用一个建立在普通实时数据库(如Firebase)之上的体育博彩应用程序的例子。 你设置了Firebase来处理你所有的登录、用户管理和实时更新。然后人们可以在应用中实时下注。
这让你开始运行,但当你的高速订单簿必须将其数据输入数据库以进行广播时,你就会开始遇到问题,而且开始花费太多时间,导致应用程序拒绝投注,或使你面临 不平衡的风险允许用户在可能过时的投注赔率上投注。
现在 有一百万用户你确实遇到了困难,因为你发出的新赔率必须复制到多个数据库,然后才能向用户推广。 这显然创造了不可接受的风险和条件。 不可接受的用户体验.
在这种情况下,数据库仍然可以成为用户数据所在的记录存储,以及交易的去向。 然而,相反,你现在可以从你现在简单得多的数据库中的状态变化中调用云函数,并将你本来要放入数据库的东西发布到你的实时解决方案中,因为在发布时调用云函数很容易。 这样,你就有了一个离开数据库的单一箭头。 你仍然可以使用数据库,但你只是在存储上调用一个动作,而不是让它尝试启动自己的广播器。
你可以做以下任何一项。
- 每个人都直接写到数据库,更新会触发一个云函数,该函数会触发你的实时广播器,将变化发送给其他人。
- 使用你的实时广播器发布消息,使用一个集成将它们直接存储到数据库。
- 你可以在每一条入站消息上调用一个云函数。
如果你去掉了数据库的实时部分--你过去对它进行一百万次读写的部分--你可以把它作为一个存储。 或者,在像Firestore这样的BaaS的情况下,它是一个做所有事情的大系统,你可以把它作为一个存储、认证层、REST API,所有的东西。 像其他很多无服务器解决方案一样,它是一个完整的后端,具有所有的好处,就像一个完美的NoSQL数据库。 在小规模下运行良好的实时功能,在严格的审查下可能不一定站得住脚。然而,这种扩展难题可以通过一个强大的实时模块轻松解决,该模块可以很好地插入你现有的解决方案中。
总结

多工具是伟大的--在一定程度上。
在一般的工程术语中,模块化是设计模式的黄金标准。根据定义,如果你想做任何具体的事情,特别是在大规模的情况下,以前的小问题或不重要的问题开始给企业带来实质性的风险,通用的一体化解决方案很少是个好主意。
如果你在考虑你的架构时是用集成实时功能的数据库,那么你就没有真正考虑你的大型用户群所需要的实际实时性。 被称为实时数据库的一类产品当然有它的位置。 Firebase的功能很好,Firestore也很好。 它们是具有整个后端服务的数据库,而且它们也碰巧提供了一些实时(-ish)功能。 这是一个非常有吸引力的价值主张,至少对于非企业规模的快速开发来说是这样。 这种权衡可能是完全值得的。
然而,专业供应商的存在有一个非常好的理由,那就是操作模块化。 实时数据库在条款上并不矛盾,至少在小规模上不矛盾,但是对于战略目的来说,它们并没有提供足够低的可扩展基元,你可以在此基础上构建。相反,它们是你必须建立的服务,或者说是围绕着它们建立的服务,迫使你的架构在未来进入巨大的复杂性。当那个时候到来的时候,你必须准备好迅速转换你的视角,超越快速和肮脏,进入更广阔的视野。
当你选择了一个数据库并有实时需求时,你通常会随着它的扩大而扩大,直到它不再满足你的需求。 我们喜欢Firebase和Firestore以及其他一些实时数据库。 他们的工作很出色,而且他们会比很多强大的解决方案更快地让你开始运作。
首要的想法是不要强迫自己进入模式,只是因为这是你当时唯一知道的事情。 解耦系统意味着你可以在任何时候扩展它们,现在或以后。 如果你能花得起时间早点考虑这个问题,以后就会有回报。 如果你必须现在就推出一个MVP--昨天!那么就把你的系统设计成可移植的。- 那么,通过对上述考虑因素的考虑,设计你的系统,使其可以在以后移植。
当实时部分最终停止扩展时,水晶球说,这是因为它从来没有打算扩展。 一直以来,我们的想法是为各自的工作选择最好的专用工具,最好是让它们能够很好地一起工作,而对彼此几乎一无所知。 真正的模块化。 每个模块内的高内聚力与具有专门任务的模块之间的松散耦合。 稳健的分布式实时计算的原则是可以扩展的。 不要试图把不自然的功能挂在你的数据库上,而是把它用于其专门的目的,并找到一个实时工具,以满足你所有严重的规模业务需求。 你的庞大用户群以后会感谢你的。
关于Ably
Ably是一个完全管理的平台即服务(PaaS),提供快速、高效的消息交换和传递以及状态同步。 我们每天都在解决实时领域的艰巨工程问题,并为之感到高兴。 如果你在尝试大规模、可预测、安全地扩展你的实时消息系统时遇到问题,请与我们联系,我们将帮助你为你的客户提供无缝的实时体验。