异步数据存储
在过去几年工作中,对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世界,我们的应用程序开发模式将发生变化。届时唯一的问题是“它会改变什么?”
- 利用HSTS安全协议柔性解决全站HTTPS的兼容性问题
- Nginx内容替换模块http_substitutions_filter_module及实用案例分享
- libmemcached编译安装报错解决记录
- 解决网站静态缓存后WP-PostViews插件不计数的问题
- Haproxy安装部署文档及多配置文件管理方案
- ASM 翻译系列第三十四弹:ASM磁盘组重要属性介绍
- 博客集成Hitokoto·一言经典语句功能
- 博客网页导致电脑CPU飙升的问题解决记录
- 恢复WordPress分类目录的别名链接形式
- 替代crontab,统一定时任务管理系统cronsun简介
- 小网站最简单实用的动静分离优化方案
- Haproxy进阶管理:命令行控制后端节点上下线
- 网站集成打字震动特效JS代码改进版
- Linux基础知识之文件隐藏属性
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法