Limbo: 简单访问远程数据库
对于 nodejs 生态来说,使用 mongoose 作为 Model 模块是再好不过的一件事,其一大特点就是简洁优雅的 Schema 定义,提供了每个键值的类型验证,数据验证,索引声明,虚拟键,并自带实例化方法的扩展,大大节省了开发的成本。但是在考虑开放数据的时候,一切就显得不那么美好了。
在打造简聊这款应用的过程中,我们就实实在在的遇到了这样的问题。由于需要使用 Teambition 的用户和团队数据,并且当简聊更新了用户数据之后,在 Teambition 中能实时的将这些更新推送到用户那里。按照惯例,我们最初使用的是 restful 接口。
第一阶段,使用 restful 接口
restful 接口的应用面最广,但是仍然存在很多不足,比如接口在参数和结构上限制较多,在考虑修改接口 api 的时候,往往会顾虑客户端的兼容性,而一旦客户端程序有新的需求,则需等待接口的更新。另一个麻烦的地方是需要做签名校验,对于内部的应用来说,我们完全可以通过防火墙来控制特定 ip 对端口的访问,签名在此处就显得有点多余。
第二阶段,单独拆封 Schema
然后我们想到了将 Schema 拆封成一个单独的仓库,nodejs 有良好的模块管理,在不同的应用中,我们只需要将这些模块引入进来,既做到同步更新,又做到 DRY。相对于 restful 接口的缺点就是,对于数据的调用入口过多,而且应用之间互相是不知情的。例如在简聊中有更新用户数据,在 Teambition 中就无法得知,并推送给其他客户端。
第三阶段,远程过程调用(rpc)
这个阶段和 restful 接口其实类似,我们在 Teambition 的后端进程中将一些接口方法暴露出来,这样我们的客户端程序就能通过简单的 rpc 方式调用这些接口。例如我们导出了 user.update
方法,在客户端代码中使用 rpc.call('user.update', params, callback)
即可调用相应的过程。这样的调用行为与使用本地代码无异,可能是目前能找到的最简单直接的方式了。
第四阶段,rpc 与 mongoose 的结合
事情可以变得更简单,由于目的主要是为了操作数据库,所以我们开发了一个模块 limbo,将 mongoose model 中所有方法暴露出来,以命名空间来划分,实现了在客户端与服务端程序一致的使用体验。
例如我们在服务端程序中使用 limbo 连接 mongodb,只需要做如下声明:(以下的代码都以 coffeescript 作为示例)
1 2 3 4 5 6 7 8 9 10 11 |
|
使用方式就与 mongoose 一致了
1 2 3 4 |
|
下面是 limbo 中最激动人心的地方,你可以导出一个 collection 中的所有方法到 rpc server 中,只需要通过一个简单的声明
1
|
|
下面我们就要提到如何在客户端程序中调用这些方法
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看出,上面的第二种方式与服务端在本地使用 mongoose 的方式一模一样,这种黑魔法式的调用方式应该是广大码农喜闻乐见的。
limbo 另一个值得称道的功能是可以在服务端程序监听这些远程调用的事件,这得益于 nodejs 的 event 对象,limbo 本身就继承于 EventEmitter 对象,所以我们在每次远程调用后会触发一个事件给服务端程序,而在服务端只需要简单的监听这个事件即可
1
|
|
正是这种 rpc 加事件反馈的机制,让简聊和 Teambition 可以实现简单实时的数据交换。我们将 limbo 托管在 github 上开源,是深知它还存在很多可以改进的地方,所以不免庸俗的说一句,欢迎 issue 和 pr~
最后,欢迎访问我们的新产品简聊,一款基于话题的轻量级协作应用。