前端网关实践

原文已发布在玩物得志技术公众号,地址:https://mp.weixin.qq.com/s/ra4F659RoY8eQcfMUvMPgw

从一个房间走到另一个房间,要经过一扇门。从一个网络向另一个网络发送消息,也需要经过一道“关口”,这道关口就是网关。

1.前言

公司在快速发展,为了更好的服务业务,前端团队在性能体验、工程化建设等方面也有了更高的追求。

NodeJs提供的服务端能力,不仅拓展了前端的能力边界,也为性能体验优化和工程化提供了更丰富的方案。

2.项目介绍

2.1 技术选型

| 框架 | 描述 |
| express | 早期的node框架,功能齐全,开箱即用。但基本停止更新,与koa最大的区别是中间件机制,虽然能实现类似koa的洋葱形调用,但是实际上依旧存在差别。 |
| koa | 没有内置任何多余的中间件,按需引入,简洁。洋葱形中间件机制,灵活。 |
| egg | 基于koa, 高度封装,功能齐全。 |

Java的SpringCloud Gateway、 和基于nginx+lua的Kong都是成熟的网关项目,但是和前端当前的技术栈不匹配。

自研一套小型网关,并根据实际需求去慢慢完善,是我们选择的方案。

总体上,我们希望网关的底层框架尽可能简洁、灵活,同时拥有高扩展性,所以最终选择了koa。

2.2 架构

前端网关内部20210219.png

2.3 执行流程

网关内部流程.png

上图是网关执行时内部的大致流转过程,请求经过多层中间件处理,

可以看到一个中间件的处理逻辑可以在请求和响应阶段发挥作用,这得益于Koa中间件的洋葱形机制 如下图:

image

下方演示了Koa中间件的写法,只需几行代码,实现一个记录访问信息和请求耗时的中间件:

const accessLog = async (ctx, next) => {

const start = Date.now();

await next();

const rt = Date.now() - start;

logger.info(`${ctx.method} ${ctx.host} ${ctx.url} - ${rt}ms`);

};

module.exports = accessLog;

请求经过中间件处理后到达服务层,服务层处理完成后返回结果,再经过中间件处理后响应。

2.4 性能&稳定

image

如上图所示,Node是**单进程 **+ **异步I/O **+ 事件循环模型,这种模型比较适合处理高并发和密集I/O的场景,不过也有一些缺陷,比如不能充分使用cpu,出现异常时整个应用崩溃等。针对这些情况,需要做一些优化:

多进程:Node本身提供了多进程方案,使用Cluster模块,只需要少量修改就能实现实现多进程,示例:

const cluster = require('cluster');

const http = require('http');

const numCPUs = require('os').cpus().length;

// 主进程逻辑

if (cluster.isMaster) {

 // 创建工作进程

 for (let i = 0; i < numCPUs; i++) {

   cluster.fork();

}

 cluster.on('exit', (worker, code, signal) => {

   // 工作进程退出后的逻辑

});

} else {

 http.createServer((req, res) => {

   res.writeHead(200);

   res.end('hello world!');

}).listen(8000);

}

有一个问题:示例里多个子进程都监听了8000端口,程序却不会报错,是因为listen方法内部判断了进程是主进程还是子进程,最终只有主进程监听了端口。最后通过进程间通信和任务调度算法来实现多进程的工作模式。

如果使用PM2来启动Node服务,无需修改任何代码也能实现多进程。 示例:

$ pm2 start app.js -i max

(max表示CPU数,如果服务器的资源可以都用来跑对应的Node服务,那么让进程数=CPU核心数算是最佳实践)

数据缓存:对外部获取的数据进行缓存,减少不必要的请求能明显提升性能。Redis是一个高性能的缓存服务,将数据缓存到Redis,不仅可以减少同进程的请求次数,也可以在多个进程间共享数据。

进程守护:默认情况下,node是没有进程守护功能的为了防止应用崩溃导致整个服务宕机,需要增加进程守护机制。

常用的两种方案:

1. 常驻进程作为守护进程

** 2. ****crontab + shell 定时检测**

进程守护的基本逻辑,都是运行程序检测应用是否正常运行,检测出异常后进行日志记录,发送警报,重启应用等等操作。

如果使用PM2来管理Node服务,无需额外操作,因为PM2自带了守护进程。

错误日志:记录运行中产生的错误日志并分析原因,能帮助我们进一步优化应用的稳定性。

3.应用场景

前端网关20210208.png

3.1 文档请求接管&动态化

区别于常见的API网关,接管来自用户的文档请求也是前端网关的应用场景。

当前前端一些项目已经改造成了微前端的形式,多个项目可以独立开发和部署,同时跨项目访问是在一个SPA应用内的路由切换。但是也带来了一定的性能损失,比如项目初始化时需要多2次串行的请求。

这种情况下,在请求经过网关时,通过微前端服务获取内容,并预注入到文档内,在初始化过程中就不需要额外发起请求,节省了2次网络请求的时间。

如下图所示:

微前端逻辑.png

通过模板服务数据预取服务、微前端服务,注入接口数据、骨架、脚本等内容,使输出的html动态化,可以有效提升首屏的访问体验。

这种方式看上去与 SSR有一些相似。相比而言,服务端预注入数据,渲染由客户端完成的方式具有更强的通用性和更低的接入成本。

主要体现在:

** 1. 业务代码无侵入** 无需大规模修改代码做适配,也不会影响原有的开发习惯。

** 2. 无框架兼容问题**无论开发框架是Vue、React, 或是自研的H5 SPA应用均可使用同一套后端逻辑。

3.2 离线文件实时更新

在App内缓存H5项目的文件,目前常见的方式有:

** 1. App打包时包含h5项目文件 **离线文件更新受发版限制,不够灵活。

** 2. 文件通过接口获取 **接口通常由后端同学提供,难以和前端工程体系打通,导致文件需要定期手动更新。

将前端发布系统与网关打通后通过离线缓存服务实时生成最新的离线文件列表并返回给客户端,实现客户端缓存文件的实时更新。

如下图所示:

离线缓存逻辑.png

4.总结&展望

当前,玩物得志h5商城的流量已全部由前端网关处理。随着业务的不断发展,后续会新增更多的Node服务和网关功能。目前网关的功能还比较简单,内集的一些服务也未做拆分,未引入RPC,我们也将持续完善网关,建设更完整健全的Node服务化体系。

本文主要分享了基于node的网关设计思路和一些实践经验。

因篇幅有限,对文中出现的一些概念未做进一步解释(如异步I/O,事件循环),对于一些值得探讨的细节(如Cluster原理、多进程任务调度、父子进程通信等等)也未做深入,有兴趣的同学请自行查阅相关资料🙈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容