异步数据存储

时间:2022-04-22
本文章向大家介绍异步数据存储,主要内容包括异步访问、数据为王、消息和数据处理的结合、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

在过去几年工作中,对NoSQL数据存储使用经验以及随着NoSQL成为主要的数据存储和检索方式,让我洞察到应用程序必经的发展方向。至少对于基于Web和基于云的应用程序而言肯定是这样的(企业应用程序最终会朝着我所说的方向发展,但这需要更长的时间)。多年来,我学会了相信自己的直觉,我强烈的第六感告诉我,我的预言是有价值的,即使我本人没有时间实现这个系统也应该有人去探索。

异步访问

我认为整个方法的核心是对数据的非阻塞异步访问。一般来说,如果我们希望在应用程序中使用异步消息传递,就必须依赖消息代理的帮助,消息代理存在的唯一目的也是异步地路由消息。坦白地讲,我最喜欢的是RabbitMQ。但是,在扩展RabbitMQ的一些关键功能时,伴随而来的更加棘手的难题却更为突出,所以我想,通过实现一个轻量级的、不依赖协议的异步库,这个异步库不像RabbitMQ那样依赖AMQP,这样或许可以加快更多环节的进展。

在我看来,Node.js促进了Web应用程序的开发形式。但真正的异步应用程序仍然比较难构建(因此在普通用户中并不常见),异步应用具有更高的可扩展性,在用户需要大量相对较小的虚拟机实例时可以更好地相互协调。消息传递是实现这一目标的合理选择。

可用的消息代理遍地都是,仅仅需要添加一些消费者,并在我们的Web应用程序中写几个生产者,这就可以了。

但我不满意,一点儿都不满意。

数据为王

如果我们将应用程序剥离为最纯粹的形式,那么我们唯一关心的就是数据。我可能会选择像我最喜欢的NoSQL数据存储Riak,因为它易于扩展,并允许在数据上执行分布式Map / Reduce。但是,数据本身首先是整个应用程序的出发点。我在应用程序内部所做的一切都围绕数据展开。我使用消息代理,消息的内容是数据;我建立一个网络表单,是为了接受数据;我生成报表,是在做数据报告。

除了数据其他都不重要。

但是消息代理不关心数据。它只是一个指挥。消息存储不关心指挥。但事实并非如此。从代码上看,下面的例子刚好说明了我的观点。

假如我需要将上传的图像转换成缩略图。为此,我写了一个简单的程序,使用ImageMagick缩放,裁剪,并将图像转换为JPEG格式。我还创建了一个Web窗体,允许用户上传他们的图像。在这个异步的数据存储世界中,我的图像转换器逻辑应该能够侦听数据存储中的INSERT或UPDATE事件并转换传入数据,自动存储上传图像的缩略图。

图像转换器伪代码:

def db = asyncdb.connect("tcp://localhost:5555") 
def img = request.get_upload_data("image") 
def metadata = [ content_type: "image/jpg" ] 
db.push("imagebucket", img.name, img.data, metadata, { event, data -> 
  if(event.type == SUCCESS) { 
    db.push("profilebucket", "$user.profile", [ avatar: data.key + ".thumbnail" ]) 
  } 
})

上述代码的作用是:

  • 连接到数据存储的节点。
  • 可以传入一个返回true|false的闭包注册数据库事件,同时传入另一个闭包在过滤条件返回true时调用。
  • 当上述代码被调用时,首先会将原始图像的版本存储在特定的按键下,同时会自动更新缩略图。

在我的Web应用程序控制器中,我将使用异步数据存储客户端插入上传的图像。


def db = asyncdb.connect("tcp://localhost:5555", [ name: "image.converter", 
                                            description: "Image thumbnailing listener" ])

上述代码的作用:

  • 连接到数据存储的节点。
  • 创建新的数据存储条目,包括足以触发缩略图监听器的元数据。
  • 将图像数据异步“推入”数据存储区并注册一个事件处理程序,以便在监听程序成功缩略图像时调用客户端的回调函数。
  • 当缩略图成功创建后,用户的配置文件将通过向其中推入新的数据进行更新,该数据引用了新转换的缩略图。

注意,一切都是以非阻塞和异步的方式完成的。数据完整性会一直保持不变,直到缩略图创建完成后才会去更新数据资料。这个系统也是无边界的。各个节点都彼此互通,所以负载平衡器可以将请求的第一部分发送到一个服务器,将请求的第二部分发送到另一个服务器,这并不会有什么影响,因为依赖于其他操作的动作会等待特定事件的触发。

消息和数据处理的结合

这种数据访问形式对我来说很有意义。虽然它可能混合了多个应用程序在传统上各自独立的部分(异步消息传递和数据存储),但它使得应用程序简洁并易于理解。

数据存储应该提供一个Web UI,以便开发人员可以查看系统的内部,看看事件是否正在等待提交。客户端方法在理想情况下也应该接受任意的元数据,Web UI可以向开发者显示,以便他们可以很容易地看到报告的监听者实际上做了什么。像下面代码所示:

def db = asyncdb.connect("tcp://localhost:5555", [ name: "image.converter", 
description: "Image thumbnailing listener" ]) 

据我所知,目前没有任何数据存储支持上述内容。可能是我是唯一真正喜欢这种东西的人。我可以向你保证,随着数据访问走向更加异步化的NoSQL世界,我们的应用程序开发模式将发生变化。届时唯一的问题是“它会改变什么?”