围绕数据流设计应用系统

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

如何构建可靠、可扩张和可维护的应用和系统? 对于任何给定的主题,都有多种解决方案,而这些解决方案都有各自的优缺点和折中之处. 本文主要是围绕着数据流思路来探索构建新型应用程序的一些方法。

数据流产生:应用程序代码作为派生函数

当某个数据集从另一个数据集派生而来时,它一定会经历某种派生函数。例如:

  • 二级索引是一种派生的数据集,它具有一个简单的转换函数:对于主表中的每一行或一个文档,挑选那些索引到列或字段值,并且按照值进行排序。(假设一个B- tree或者SSTable索引)
  • 通过各种自然语言处理函数(如语言检测、自动分词、拼写检查和同义词识别)创建全文搜索索引,然后构建用于高效查找到数据结构
  • 机器学习系统中,可以考虑通过应用各种特征提取和统计分析功能从训练数据中导出模型。当应用和新输入数据时,模型的输出是基于输入数据和模型派生而来。
  • 缓存通常包括那些显示的在用户界面的聚合数据。因此填充缓存需要知道在UI中引用哪些字段。

二级索引是核心特性,一般都内置于数据库。对于全文索引,一般的语言方面的函数也会内置于数据库,但更复杂的特性通常还需要针对特定领域进行调整。而对于机器学习,众所周知特征工程和特定应用紧密相关,因此还需要集成很多用户交互和部署方面的详细知识。

如果创建派生数据集的函数并非创建二级索引那样标准,就需要引入自定义的代码来处理特定应用相关。一般是应用程序代码作为派生函数。

应用程序状态和代码分离:微服务VS订阅流?

数据库无法满足当今应用程序的很多开发要求,如依赖性和软件包管理,版本控制,滚动升级,监控指标,网络服务调用和外部系统的集成等。

系统的某部分专注于持久性数据存储,同时一部分专门负责运行应用程序代码是有道理的。现在大多数web都被部署为无状态服务,用户请求可以被路由到任意的应用程序服务器上。数据库充当一种可以通过网络同步访问的可变共享变量。

有变化的状态和应用程序的相互影响,目前的应用程序主要是这么实现的。

目前的应用程序开发风格一般是REST风格,并分解为一组通过同步网络请求进行通信的服务(RPC微服务)。这种结构相比单体结构,在于更好的组织伸缩性:不同的团队可以在不同的服务上工作,减少了团队之间的协调工作。

数据流系统和微服务理念有很多相似的特征,但底层的通信机制差异很大:前者是单向、异步的消息流,而不是同步的请求/响应交互。 订阅变化的流,而不是在需要时去查询状态(当某些数据变化时,依赖于此的派生数据都可以快速更新),使得可以围绕数据流来构建应用程序。

派生状态剖析-读写路径

前面讲到的数据流系统主要侧重如何创建派生数据集并使其保持最新状态。我们可以把这个过程称为写路径:只要有信息写入系统,它就可能经历批处理和流处理的多个阶段,最终每个派生数据集都会更新以包含新写入的数据。比如下面的搜索引擎:

image.png

为什么要创建派生数据集呢?因为想在以后多次读取它:用户访问时做些必要的处理并返回结果。

总之,读路径和写路径覆盖了数据的整个过程。写路径可以看作是预计算的一部分,一旦数据进入,即刻完成,无论是否有人要求访问它。读路径是只有明确的访问时才会发生。 读写路径可以认为是写入时需完成的工作量和读取时需完成的工作量之间的一种平衡。

应用程序客户端

应用程序客户端是离用户最近的地方。从这里可以继续探讨下读写边界的问题

有状态、可离线客户端

web浏览器是无状态的客户端,只有当互联网连接时才能触发后面的处理。 然而,JavaScript Web应用程序已经支持很多有状态的功能,包括基于客户端的可交互用户界面和数据持久保存在Web浏览器。移动应用程序类似的可以在设备上保存很多状态,并且很多交互不需要与服务器进行往返通信。它们使用本地数据库,在网络连接可用时与远程服务器同步。

离线工作,对用户来说是一个巨大的优势。

当我们摆脱无状态客户端与核心数据库这样的假设,而转向在终端用户设备上维护状态时,就打开了一个全新机遇。特别是,我们可以将设备上的状态视为服务器上的状态缓存(实体化视图)

状态更改推送至客户端

普通的HTTP请求响应模式,而比如WebSocket之类的协议则将状态更改推送至浏览器或客户端,这样的通信通道可以使得服务器和客户端之间保持开放的TCP连接,只要处于连接状态,服务器就可以主动推送消息至浏览器。

这为服务器提供了主动通知并更新终端用户客户端本地存储状态,从而缩小与服务器状态的滞后程度。

就上面读写边界的问题而言,写路径一直延伸到终端用户。

客户端首次初始化时,仍然使用读取路径来获得初始状态,此后依赖于服务器发送的状态更改流。可以看出,流处理和消息传递方面的这些想法并不局限于在数据中心运行,可以进一步将这些想法扩展到终端用户设备

为了将写路径扩展到最终用户,我们需要从根本上重新思考构建这些系统的方式:从请求/响应交互交互转向发布/订阅数据流

猜你喜欢

转载自juejin.im/post/7114055837567418375