项目名称:关于 node.js 在公司基础框架中的应用
修订历史:
版本号 | 作者 | 时间 |
---|---|---|
1.0 | 廖石荣(0027011057),林飞鹏(0027011438) | 2019-01-11 |
1 概述
1.1 术语
Node.js 是一个 Javascript 运行环境(runtime environment),发布于 2009 年 5 月,由 Ryan Dahl 开发,实质是对 Chrome V8 引擎进行了封装。Node.js 不是一个 JavaScript 框架,不同于CakePHP、Django、Rails。Node.js 更不是浏览器端的库,不能与 jQuery、ExtJS 相提并论。Node.js 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。
1.2 需求背景
最近部门某个项目在开发完成初次上线之后,由于接口复杂,数据库设计等原因导致接口返回超时,特别是多人同时使用这个系统,并发性存在问题,后来通过后端将接口由串行改为并行方式返回数据,数据库增加索引等方式虽然解决了问题,但是花费的时间比较多而且复杂,所以后来在想有没有一个好的架构可以避免这种问题,由于毕业设计的时候接触过 node.js,我知道 node.js 可以解决高并发,它是单线程,当访问量很多时,将访问者分配到不同的内存中,不同的内存区做不同的事,以快速解决这个线程。就像医院的分科室看病人。效率快,但消耗内存大、异步和事件驱动。概扩起来就三点:单线程、异步 I/O、事件驱动。nodejs 离不开 ChormeV8 引擎,也就是 V8 引擎是来解释 javascript。用 nodejs 来搭建高性能的 Web 服务器,因此 node.js 是基于服务器端的 javascript。
由于项目规模越来越大,前后端分离必然是个趋势,当前的分离模式如下图:
后端 | 前端 |
---|---|
提供数据 | 接收数据,返回数据 |
处理业务逻辑 | 处理渲染逻辑 |
Server-side MVC 架构 | Client-side MV* 架构 |
代码跑在服务器上 | 代码跑在浏览器上 |
这里分离干净了,分工也很明确了,看似一切都那么美好,but...我们也很容易发现问题的所在:
- Client-side Model 是 Server-side Model 的加工
- Client-side View 跟 Server-side 是 不同层次的东西
- Client-side 的 Controller 跟 Sever-side 的 Controller 各搞各的
- Client-side 的 Route 但是 Server-side 可能没有
也就是说服务端和客户端各层职责重叠,大家各搞各的,很难统一具体要做的事情。并且可能会伴随着一些性能上的问题。最具体的表现就是我们常用的 SPA 应用:
- 渲染,取值都在客户端进行,有性能的问题
- 需要等待资源到齐才能进行,会有短暂白屏与闪动
- 在移动设备低速网路的体验奇差无比
- 渲染都在客户端,模版无法重用,SEO 实现 麻烦
紧接着,我们代码量越来越大,我们需要校验的表单也会越来越多,有时候,前端提交需要校验一次表单。
服务端任需要进行校验来达到数据的可靠性;前端的路由可能在服务端并不存在....等等这一系列重用性的问题。所以我们之前的重构可能需要更深层次的思考。
1.3 目标
高可用,高并发,稳定性,速度快
2 系统构架重构
在开始重构之前,我们需要对前后端界线做一个划分,也就是说什么是属于前端的范畴,什么是属于后端的范畴,最传统的前后端划分可能是这样的:
那么问题来了:我们前后端划分的接线,是依照工作职责来划分的前后端;还是依照硬体环境划分的前后端?自从了 nodejs 之后,我们可以从工作职能上重新定义前后端的范畴:
可以看到,这里的前端比之前多了个 nodejs,也就是在前后端之间我们构建了一个 nodejs 服务作为中间层!
为什么我们选择的中间层是 nodejs 呢?因为我们把中间层归在了前端的范畴,那么对前端小伙伴来说,nodejs 毕竟还是个 js,那么从语法角度来说,上收起来应该没有什么问题。其次开发转移成本也想对较低,不必来回切换语言的逻辑和语法:
- 前端熟悉的语言,学习成本低
- 都是 JS,可以前后端复用
- 体质适合:事件驱动、非阻塞 I/O
- 适合 IO 密集型业务
- 执行速度也不差
好了,提前说了这么多东西,那么这个中间层能给我们带来什么了?要知道引入 nodejs 的开发成本也是很大的,首先就是多了一层服务,多的不说,单凭传输时间,就多了一层的传输时间啊!下面我们来研究一下什么应用场景下的 nodejs 能给我们带来利大于弊的东西。
3 中间层应用场景以及性能问题
引入 nodejs 之后,我们来重新划分一下前后端的职能:
这个就是中间层 nodejs 的主要思路,下面我们来看一下常见的业务场景:
3.1 常见业务场景
3.1.1 接口数据可靠性修复
有的时候服务端返回给我们的数据可能并不是前端想要的结构,所有用到的展现数据都是后端通过异步接口(AJAX/JSONP)的方式提供的,前端只管展现。但是后端经常提供后端的数据逻辑,在前端还需要去处理这些数据逻辑。比如我再开发一个功能的时候,有时候会碰到这样的问题:
服务端返回的某个字段为 null 或者服务端返回的数据结构太深,前端需要不断写这样的代码去判断数据结构是否真的返回了正确的东西,而不是个 null 或者 undefined:
if (params.items && params.items.type && ...) {
// todo
}
对于这种情况,我们前端其实不应该去重复校验数据的格式,这也本不应该是浏览器端 js 需要做的事情。我们可以在中间层做接口转发,在转发的过程中做数据处理。而不用担心数据返回的问题:
router.get("/buyer/product/detail", (req, res, next) => {
httpRequest.get("/buyer/product/detail", (data) => {
// todo 处理数据
res.send(data);
});
});
3.1.2 页面性能优化 和 SEO
有点时候我们做单页面应用,经常会碰到首屏加载性能问题,这个时候如果我们接了中间层 nodejs 的话,那么我们可以把首屏渲染的任务交给 nodejs 去做,次屏的渲染依然走之前的浏览器渲染。(前端换页,浏览器端渲染,直接输入网址,服务器渲染)服务端渲染对页面进行拼接直出 html 字符串,可以大幅提高首屏渲染的时间,减少用户的等待时间。这种形式应用最广的比如 Vue 的服务端渲染,里面也有相关的介绍。
其次对于单页面的 SEO 优化也是很好地处理方式,由于目前的 ajax 并不被搜索百度等搜索引擎支持,所以如果想要得到爬虫的支持,那么服务端渲染也是一种解决方法。
3.2 中间层性能问题
多加了一层通讯,肯定会有一定的性能损耗。但分层带来的损失,一定能在其他方面的收益弥补回来,而且合理的分层能让职责清晰、方便协作,大大提升开发效率。也可以通过优化通讯方式和协议,尽可能把损耗降到最低。
一个静态化的详情页面上有很多(动态)的数据,用户资料、评论信息、订单等等,需要 5、6 个异步请求,node 中间层可以代理这些请求,轻松实现 Bigpipe。
在 PC 上你觉得发 5,6 个异步请求也没什么,但是在无线端,在客户手机上建立一个 HTTP 请求开销很大,有了这个优化,性能一下提升好几倍。
3.3 容易拓展多种语言接口
目前 Node.js 可以支持调用 python , c++ 等其它语言接口,这样可以每个模块选择最优技术语言解决方案,不用局限于 Java 一种语言了,技术壁垒也可以打破。
3.4 淘宝常见的需求解决方案
需求:在淘宝,单日四亿 PV,页面数据来自各个不同接口,为了不影响体验,先产生页面框架后,在发起多个异步请求取数据更新页面,这些多出来的请求带来的影响不小,尤其在无线端。
解决方案:在 NodeJS 端使用 Bigpiper 技术,合并请求,降低负担,分批输出,不影响体验。同时可以拆分大接口为独立小接口,并发请求。串行 => 并行,大幅缩短请求时间。
3.5 开源的成熟方案
目前 Node.js 业界比较成熟的方案很多,如:
- express
- koa
- sails
- loopback
- thinkjs
- egg
express
这个是使用最多的框架,也是各个推荐新手入门的框架。
Express 不对 Node.js 已有的特性进行二次抽象,只是在它之上扩展了 Web 应用所需的基本功能(个人感觉相当于 node 中的 jquery)
- 封装了路由
- 静态资源托管
- 中间件的概念
- 内置了 jade,ejs 模板引擎
个人评价,express 适合小型项目,不适合大型企业级项目,个人用用还可以,做为快速入门是个很好的选择,用过之后就可以考虑进入 koa 框架的道路
koa2
koa 是比 express 思想更先进的框架,是 express 原班人马打造
koa 解决的最大问题,利用 async await 的新语法特性,解决回调地狱的问题
koa 与 express 最大的不同,个人觉得有 3 点: 1.在于 handler 的处理方法,express 是普通的回调函数, koa 是利用 ES7 中 Async/Await 的特性,没有回调,没有回调,就大大加速了开发速度这一点而言,已经足以让我们跪舔了
2.koa 是洋葱中间件模式,执行到 next 的时候,会去调用下一个中间件,下个中间件执行完再接着执行上个中间件 next 下面的代码
3.koa 把 request, response 封装到了同一个上下文对象 content
最为 express 的进化,确实带来更好的开发效率,成本只需要学西一下 async await 的新语法特性。可以说作为 express 框架的进阶框架是非常好的了
后面的这几个都是企业级框架
express =》koa 之后,最大的问题就是开发项目的时候缺少约束,单人开发还好,多人的时候,各种目录结构,各种包的选择,百花齐放的代码风格。都是团队开发头疼的事情。
因为本人之前做过 php 开发,laravel 框架的使用起来很舒服(优雅!),还有配套的 laravel-admin。所以一直想找一个能像 laravel 这样的 node 框架提高开发效率
回到正题,sails , loopback, thinkjs, egg 都是企业级框架,我们又该如何选择
Sails 是基于 exrpess 的大而全的框架,MVC 框架,旨在模拟熟悉的 Ruby on Rails 框架的 MVC 模式,但支持现代应用程序的需求。捆绑了一个强大的 ORM,即 Waterline。自动生成的 REST API
LoopBack 是建立在 Express 基础上的企业级 Node.js 框架,只需编写少量代码就能创建动态端到端的 REST API,一致化的模型关系和对 API 访问的权限控制等
ThinkJS 是国内 360 团队推出的一款面向未来开发的 Node.js 框架,整合了大量的项目最佳实践,让企业级开发变得如此简单、高效。框架底层基于 Koa 2.x 实现,兼容 Koa 的所有功能
Egg.js 是《阿里旗下产品》基于 Node.js 和 Koa 的一个 Nodejs 的企业级应用开发框架,它可以帮助开发团队及开发人员降低开发和维护成本。Egg.js 则是按照约定进行开发,奉行『约定优于配置』,具备提供基于 Egg 定制上层框架的能力、
高度可扩展的插件机制、内置多进程管理、基于 Koa 开发,性能优异、框架稳定,测试覆盖率高、渐进式开发、开发成本和维护成本低等特点。
4 总结
4.1 对现有团队的影响
常见的前后端分离的开发模式中,后端为前端提供了路由结构和页面的数据绑定,前端只需要切页面和少量的逻辑。
在 node 中间层中,前端不仅仅要切页面和做页面逻辑,还要做 url design、页面数据绑定、联调与沟通,还要考虑 SEO 的问题,伪静态页面、title/keyword 设置、网站地图,甚至包括错误日志等等。虽然前端的工作量增加了不少,但是基于模块化的开发,让总体的效率提升了。
对于后端程序员,接口整合的工作交给了前端服务器进行处理,同时和前端耦合度大大降低,工作量和工作效率都减少了。
另外,由于前后端分离,测试都可以分开来了,专门测试接口的和专门测试 ui 层。分析项目对本系统的影响,例如:
- 新加的业务,功能有没有影响原有的功能
- 系统的改造对原有业务有什么影响
- 有没有影响系统对外提供的服务的约定,这非常重要
4.1 个人期望
我觉得,以后基于 NodeJs 的全栈式开发的模式将会越来越流行,这也会引领前端步入工程化时代。但是要把 Node 全栈开发变成一个稳定的、方便的开发工具,还有很多路要走。公司也可以一步一步慢慢往这个方向上靠拢,打造高可用的框架平台产品。
本文部分图片段落参考文章: 淘宝前后端分离实践