Kanro - RESTful 后端框架(01)- 遇见 Kanro

Kanro 简介

Kanro 是一个基于 NodeJS 的轻量级的后端框架。

什么是 Kanro?

Kanro 是由我开发的基于 NodeJS / TypeScript 的一个 RESTful 后端框架,隶属于 Project Marduk 计划。其采用了模块化开发的方式,将 HTTP Request 的处理阶段抽象成多个接口,使各个模块之间的松耦合,并且能够自由组合,实现各种各样的需求。Kanro 采用 npm 作为模块间的版本的管理,让开发到预上线只需要一条命令,并且可以多个版本模块并存,保证后端的稳定型。

开发 Kanro 的灵感是什么?

最近对后端来说,“微服务”的概念比较火热,其核心就是将业务逻辑拆分成多组内部服务,通过服务间的调用来完成业务逻辑,而不是传统的单体应用的概念,并且服务间完全独立,达到高可拓展性,高可用性。

Kanro 也是从微服务的概念而来,只不过采用“模块”来取代微服务中的“服务”的概念,Kanro 的每个组件都是一个“模块”,模块可以动态的载入到 Kanro 核心中,并通过动态的更新配置来使模块功能上线。

在一个产品发展的途中,负载可能并没有达到将整个后端微服务化的程度,而且微服务化后端也会带来一定的性能损失,例如出现在服务间调用时的性能消耗。所以在产品初期时就进行微服务化一般是弊大于利的,只有当负载达到一个数量级,这个时候的微服务就是提升整个后端负载能力的利器,但是如果没有一个好的后端设计作为开始,微服务化是一个非常艰难的工作。

所以 Kanro 诞生了,Kanro 是一个“假的”微服务框架,利用本地调用与动态模块加载来实现微服务的特性,但是 Kanro 还是一个单体应用,但由于其中的思想,特别易于将业务逻辑抽离成为一个微服务。并且 Kanro 本身是可以实现微服务的,你可以在服务器上运行多个基于 Kanro 的微服务应用,而且之前所写的模块不需要任何修改仍然可以继续使用,这样可能进行轻松的微服务化。

Kanro 的完成度?

现在的 Kanro 完成度还不高,我们不建议您用于生产环境中,但是我们希望能有一个良好的社区来支持 Kanro 的发展,Kanro 是一个完全开源的项目,每个人都能参与到 Kanro 中的发展,一个 Bug 反馈,一个 PullRequest,一条建议,都是对 Kanro 的发展的贡献。

为什么采用 NodeJS + TypeScript这样的组合?

NodeJS 平台的非阻塞式的 IO,我觉得特别的适合作为后端平台。JavaScript 的万物皆实例的对象设计特别适合我们的框架模型,不会有模块版本冲突。NPM 的包管理器也适合作为我们的模块管理器,私有仓库,发布,版本控制等特性拿来即用。TypeScript 极大的提高了开发效率,也隐藏了 JavaScript 的一些实现的丑陋的细节(主要是 async/await ),让我们专注于 Kanro 的开发而不是与 JavaScript 丑陋的细节做斗争,另外还有一点,我是个 C# 程序员。

Kanro 的设计模型

Kanro 作为核心,模块作为组件,Executor 与 Service 作为处理单元,构成整个后端网络。

Kanro 模块的组成

一个 Kanro 模块由各种 Executor 与 Service 组成,一个 Kanro 模块代表者一系列的功能组件,这些功能组件有些是公用的,有些是特例化的,比如对 API 请求做校验,可以是公共的,处理一系列预定义好的异常的异常处理器也可以是公共的。再举个栗子,对于某个特定业务的处理可以是一个特例化的。

对于模块开发而言,我们建议开发者仔细考虑每个功能组件的职责,并将一类功能组件放到一个模块中。不要过度聚合也不要过度拆分每个模块。

Kanro 功能组件

Kanro 的功能组件有两种,分别是 Executor 与 Service。

Executor 是最基本的处理单元,我们通过它们的功能,对 Executor 进行了一些功能上的抽象,来完成几乎所有需求。例如:基于请求处理器的校验器,基于请求分流器的负载均衡与断路控制器。

Service 是每个处理单元可使用的服务,其概念类似于微服务架构中的单个微服务,服务提供了一系列的功能。例如:对某个数据库的操作,可以成为一个服务。

Kanro Executor(基本处理单元)

在前面我们知道了 Executor 是 Kanro 框架中的最基本的处理单元,Executor 会对每个请求进行处理,响应。我们把 Executor 按照功能分为了 10 种。

  1. 请求处理器

    会处理请求,但是并不会提供响应,可以当作请求处理器的可以有:校验器、Body parser、文件上传处理。

  2. 请求分流器

    会对请求进行分流,可以当作请求分流器的可以有:请求路由器、负载均衡、断路控制。实际上 Kanro 提供的默认的请求路由器就是基于请求分流器实现的。

  3. 请求复制器

    对请求进行复制,我们 HTTP 的请求与响应是一一对应的关系,所以请求复制器会将下游第一个 Executor 返回的响应作为最终响应输出给客户端。请求复制器好像并不是特别的常用,但是我们对请求复制器的应用场景有着比较明确的定位,例如 Kanro 已经无法满足您的需求,并且您已经准备好了一个新的后端应用,这个时候可能需要测试一下新的后端应用的,这个时候就可以使用请求复制器,将 Kanro 收到的请求复制给新的后端应用。还有一个场景,请求复制器可能就会非常的有用,例如您的数据库需要更换,可以通过请求复制器同步两个数据间的数据更改,用于测试数据库更换的可用性。

  4. 响应器

    响应器是处理请求的最后一步,在这个步骤里,请求会被处理成响应,也是整个处理链路的主流程。

  5. 响应处理器

    响应处理器能够对响应进行处理,我们拟定的场景是,对响应的格式映射,或者是对响应的校验。

  6. 异常处理器

    异常处理器可以附加在任何一个 Executor 上,当这个 Executor 或者其下游 Executor 抛出异常时,异常处理器能够被执行,如果异常处理器能理解并处理这个异常,就会返回一个响应,我们对异常处理器的拟定的使用场景是处理一些预定义好的异常,例如由校验器抛出的校验失败异常,由路由器抛出的没有路由异常,并将其转换为 401,404 之类的信息

  7. 保险丝

    保险丝非常类似于异常处理器,但是异常处理器是将异常转换为响应,但是保险丝是将异常转换为请求并转发给下一个 Executor。当有一个异常发生时,如果保险丝能理解这个异常,甚至不需要理解异常,就走一条备用的路线。我们对异常处理器的拟定的使用场景是,提供一个简单服务降级的功能,例如一个 API 有两种实现方式,A 方式不可靠,但是效率高,B 方式可靠但是低效,我们可以用一个保险丝放到 A 方式的链路下,并与 B 方式的链路链接,这样当 A 链路发生异常时,可以自动调用比较可靠的 B 方式

  8. 全局请求处理器

    全局请求处理器是所有请求都会经过的地方,我们可以在这里做一些对请求统一处理的事情,例如:日志的纪录、全局的请求校验器,全局的 Body parser

  9. 全局响应处理器

    全局请求处理器是所有响应都会经过的地方,我们可以在这里做一些对响应统一的事情,例如:日志的纪录,全局的响应校验器

  10. 全局异常处理器

    全局异常处理器使用场景,大概就是为链路上的异常提供一个对用户友好,对开发者友好的呈现方式,例如:返回一些错误信息用于 Debug。

Kanro Service(组合业务逻辑)

Service 其实是一种特殊的 Executor,和 Executor 最大的区别就是 Service 不参与处理链路,Executor 通过注入依赖获取到 Service,并且 Service 是单例的,也就是同一个模块的一个名字的 Service 只会有一个实例。

Service 是 Kanro 从微服务架构中吸取的精华,Service 用于提供一系列基础的业务功能,例如访问数据库,如果您拥有多个数据库,那么 Service 是对您分离每个数据库的业务的最佳工具,每个数据库都可以提供一个 Service,用于不同的 Executor。将一类业务通过 Service 的方式聚合在一起,这是我们对 Service 的定义。如果您没有多个数据库,也没关系,通过 Service 将数据库中的表的业务分离开来,也是一个不错的方式。

由于 Service 是由 Kanro 进行管理的,我们建议的开发方式为,实现逻辑打包给 Kanro 使用,并且单独打包一份 TypeDefine 提供给开发 Executor 使用,并且使用接口的方式暴露给实际的 Executor。

一句话简介 Kanro 模型

Executor 与 Service 通过业务分类组成模块,Kanro 动态载入模块并通过配置将 Executor 与 Service 组装在一起,形成业务逻辑。

源代码

ProjectMarduk/Kanro 基于 MIT 协议开源。

结束

关于 Kanro 的介绍就到这里,下篇文章我们会一起开始搭建一个 Kanro 环境

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章