js延时函数_基于Serverless一站式Node.js服务管理平台实践

89c7854fa1421813b46fad6e1ced50af.png

导语

本文阐述了基于Serverless搭建一站式node服务管理平台过程中,在开发框架、日志、监控、部署等方面遇到的问题及技术方案。

背景

Serverless是一种无服务器架构,它的弹性伸缩,按需使用,无运维等特性都是未来的发展方向。但是如何充分的利用Serverless的优势是一个需要探索实践的问题。本文介绍的SFF(Serverless For Frontend)一站式node服务管理平台,基于Serverless服务提供一套node服务整体解决方案,解决目前公司内node服务的以下痛点问题:
1、node服务无法根据负载弹性伸缩,突发流量大时有雪崩风险。
2、node服务无法平滑高效迁移Serverless函数型服务。
3、全栈项目无统一规范,无统一构建部署流程及工具。
4、node服务运维困难,无完整监控、性能分析、故障排查手段。
让开发者专注业务开发,提升开发和运维效率。本平台整体功能结构如下:

955fd06c44721ef5ea3288dc9653e40a.png

下面对其关键功能实现进行阐述。

全栈工程开发方案

SFF的脚手架提供了全栈开发的项目骨架,其中包含了前端工程和后端工程,这里面的问题是如何进行前后端工程的文件组织?传统的开发中,前端工程开发页面时需要mock后端工程的api数据,后端工程开发api时依赖前端页面的请求,如何在本地高效进行前后端项目的开发联调?如何在部署阶段进行前后端项目的统一部署?我们的解决方案如下:
1、前端工程与后端工程分别存放在client与server文件夹中,拥有独立的package.json文件,优点是对于依赖的npm包及运行时的文件依赖可以做到解耦合。
2、node端开发了静态资源插件egg-wb-static,该插件能够实现前后端工程无需mock数据或者mock api请求,达到开发阶段即联调的效果。

19dff33963a28a5f83ec8c4b67fe69c6.png

其原理是在本地开发时访问后端工程服务,这样本地开发和线上部署访问方式一致,该插件将静态资源的请求代理到前端工程的dev server,所以拥有前端工程本地开发的热更新等能力。在部署阶段,静态资源部分上线到cdn,模版资源放入node项目中,该插件又提供了渲染页面的能力。


3、结合 npm script + 构建部署命令 + 不同部署环境的环境变量 + docker镜像,实现了构建阶段的依赖安装、打包,产出上线静态资源包+部署镜像。

前端工程化方案

我们采用webpack作为前端工程的构建工具,面对的问题是如何标准化简洁化构建配置,如何统一管理构建相关依赖?

方案一:

全局脚手架负责:初始化项目骨架。
项目总负责:
1) webpack工程化配置。
2) 构建依赖:babel相关、资源loader相关、webpack插件...
3) 运行依赖: vue、vue-router、vuex...

fffe38aaf54ed22236aafda47e12d1c8.png

优点:
各项目独立,构建不依赖全局脚手架。
缺点:
脚手架只起到初始化项目骨架的功能,无法统一升级项目构建依赖及工程化配置。

方案二:

全局脚手架负责:
1) 初始化项目骨架。
2) webpack工程化配置。
3) 构建依赖:babel相关、资源loader相关、webpack插件...
项目总负责:
简洁工程化配置。
运行时依赖: vue、vue-router、vuex...

7baf09891d5eda17b347f3eb4747986e.png

优点:
可以统一升级构建依赖及工程化配置。
缺点:
1) 多项目依赖不同版本全局脚手架问题。
2) 构建依赖在全局 很多babel-loader less-loader的模块查找机制 都是在当前执行命令的目录进行,需要通过hack的方式实现在全局脚手架的依赖中查找。
3) 影响webpack打包,在文件内容不变情况下,构建文件内容不一致。webpack打包时会对每一个模块进行包装都是与文件的位置相对于当前项目根目录的位置相关,所以如果项目和全局脚手架的之前的相对路径改变 即使代码没有改动,打包出的文件的hash值也会不同。

方案三:

结合方案一和方案二的优点,我们需要实现的是,可以统一升级项目构建依赖及工程化配置,并且各项目不依赖全局脚手架。
全局脚手架负责:初始化项目骨架。
构建集合包负责:
1) 构建依赖:babel相关、资源loader相关、webpack插件...
2) webpack工程化配置。
项目负责:
1) 运行时依赖: vue、vue-router、vuex...
2) 构建依赖:构建集合包。
3) 简洁工程化配置。
全局脚手架只负责初始化项目骨架,把管理构建依赖和工程化配置的功能单独抽离为构建集合包放入项目依赖中。

9fa1dc3c74fccbe6107fe4a82bcb92dd.png

优点:
1) 可以方便用户统一升级构建及工程化配置。
2) 各项目之前无相互影响。
3) 所有依赖都在项目node_modules下,不影响webpack打包。

日志处理

日志的处理对于web服务至关重要,面对的问题是如何标准化用户的日志输出?如何在不影响业务的情况下进行准实时上报?如何能够让用户通过更方便的查询日志?SFF平台提供了如下解决方案:

ec2184ee93b05daf5329cdca481e3827.png

1、提供日志输出模块。该模块负责标准化用户的日志输出格式,用户引用该模块进行日志的打印,格式如下:

4b834d6d9bd8bce26415366d8b2d48cb.png

2、开发日志访问中间件,集成到node框架中集成在node框架中作为第一个中间件,帮助用户自动化记录web服务的每一个请求。
3、日志收集

  • docker容器接管node服务标准输出流,将服务日志打到宿主机器。
  • 宿主机器上Fluentd将日志收集到日志服务器。
  • 再由logstash消费到Elasticsearch。
  • 用户可以通过kibana对日志进行多方位查询。

进程监控

对于前端代码的问题排查,浏览器的调试工具为我们提供了极大的便利,类比到node服务中,我们的代码部署到了服务器上,对我们是个黑盒,无法分析它的运行状况。SFF平台node服务进程的监控做了如下工作。

1、监控数据的收集

1) 内存占用
node的process模块提供了memoryUsage方法,返回 Node.js 进程的内存使用情况的对象,该对象每个属性值的单位为字节。
rss 是驻留集大小, 是给这个进程分配了多少物理内存,这些物理内存中包含堆、代码段、以及栈。
heapTotal:堆占用的内存,包括用到的和没用到的。
heapUsed:用到的堆的部分。
external 代表 V8 管理的,绑定到 Javascript 的 C++ 对象的内存使用情况。

589ce4b7dfbf9ea8a65e265190b88cd3.png

2) cpu使用率的计算
cpu使用率 = 单位时间内cpu的使用时间/单位时间。
可以通过定时器 + process.cpuUsage返回单位时间内cpu的使用时间,但是这里注意单位时间的计算不能采用设置的定时器间隔时间,一方面存在程序运行是定时器执行延时,另一方面定时器时间不精确,因为process.cpuUsage返回的时间精确到微秒(百万分之一秒)。需要使用process.hrtime返回定时器执行精确的时间间隔。
3) cpu profile收集与火焰图展示
采用v8-profiler进行cpu profile 数据的收集,每秒采样次数在700次上下,该工具可记录每次采样时正在执行的函数及其调用栈,以树状结构的形式进行返回,其节点的关键数据结构如下:

{  "functionName": "(root)", // 函数名称  "url": "", // 文件位置  "lineNumber": 0, // 函数所在行数  "hitCount": 0, //采集次数  "id": , 节点id  children: [] // 子函数调用节点}

对节点的遍历,给每一个节点添加如下字段:
depth:节点深度 = 树的深度。
hitCount:节点的采集次数 = 所有自己的节点采集次数+当前节点采集次数。
execTime:执行时间 = 该节点的采集次数 * 每次采集的单位时间。
percentage:执行占比 = 该节点的采集次数/该节点的父节点采集次数。
最后利用,用svg进行火焰图的渲染,每一个节点为一个渲染单元,按照节点深度和执行占比确定svg元素的定位与尺寸,深度为0的节点为火焰图最底层。

2、监控数据上报

以上阐述了监控数据的收集,下一个问题是数据的上报。我们的需求是用户能够监控部署在SFF平台上的node进程实例,每一个进程的cpu和内存情况,并可以指定进程进行内存快照和cpu profile的截取和分析。针对以上需求我们做了如下方案实现:
1) 数据的传输方式采用node进程与SFF服务建立TCP连接。
2) node进程的标识:docker机器名称 + 应用名称 + 进程id。
3) 存活的node进程维护在redis中,供用户查询。
4) SFF服务定时对存活进程下发采集cpu和内存的指令,并将数据上传到mongodb中存储(数据量小,保留2天)。
5) 内存快照与cpu profile 上传到公司云存储服务,保存文件地址到mongodb。
看似已经实现了功能,但是当SFF服务同时作为HTTP server和TCP server,并多实例(node多进程与多机器部署)部署时遇到了问题。用户发送的采集快照指令可能发送不到node进程中,原因如下图:

547a17871398f1e04adb3fa0d21b8e76.png

当 HTTP请求发送收集node A的命令,并负载均衡分配到了instance A,但是与node A建立TCP连接的socket对象却在instance B上。
总结问题出现的原因有如下几点:
1) SFF平台多实例部署。
2) http命令连接的SFF服务实例是不确定的。
3) node进程连接的SFF服务实例是不确定的。
4) node进程的socket对象是不可在SFF实例间共享。
采用解决方案:利用Redis的订阅发布机制实现SFF服务间的通信,SFF实例启动时进行事件订阅,HTTP收集命令触发Redis事件发布,订阅的事件中判断指定node进程的socket是否在当前实例,如果在则发送tcp指令。

8b50d1b01634b946ecf4dbbc78e3fd1c.png

一键部署

SFF平台对于完整的全栈项目上线过程分为:镜像构建、部署静态资源、部署node服务,平台提供图形化手工操作流程。但如果在命令行中执行一条命令就自动化的完成以上步骤,就能够为开发者节省大量时间。
实现思路是在命令行工具中按流程调用SFF平台提供的接口,但需要解决的问题是识别用户身份,校验用户权限,因为SFF平台的接口通过cookie中信息识别用户身份,但是命令行中无法带cookie信息,也无法跳转登录界面。采用的解决方案是用户可以在平台上生成独一无二的一串密钥,并将密钥与用户身份存入mongodb中,用户可随时更新。本地命令行工具提供设置密钥的命令,设置密钥后,一键部署命令的请求都将带着密钥,SFF服务的校验权限中间件中增加对密钥的解析,进行身份认证。

Serverless方案对比

1、web服务型函数

目前业内还没有serverless的统一标准,函数即服务在一些场景下有其优势,但是对于传统node开发的web服务来说,第一改造迁移成本巨大,第二开发维护成本和资源占用也会比统一的web服务成本高。所以SFF在Serverless基础上,实现的是web服务型函数,已有项目可以低成本快速迁移,不增加开发维护成本。

2、冷启动问题

Serverless是按需使用,弹性伸缩,理论上当函数访问频率低会被回收,再次被访问时,重新启动服务,目前各大云平台对于函数的访问都有一定的启动时间。考虑到web服务的特殊性,SFF针对web服务型函数,默认维持1个实例的存活,解决web服务冷启动问题。

3、日志监控问题

各大云函数平台都实现独立实现了函数日志查询和函数调用监控,SFF针对web服务定义了标准的日志格式,结合公司内ELK日志解决方案,针对node服务定制了监控和性能分析手段。

总结

Serverless技术已经来临,发挥其最大价值的方式就是探索实践其落地应用场景。SFF平台目前已支持公司内部多条业务线使用,每月500+次构建、300+次node服务部署、300+次静态资源部署。总结起来SFF的实践经验包括了在开发环节提供脚手架工具、多套项目骨架、node框架及周边插件、前端工程框架;在构建部署阶段,提供统一快速稳定的服务;在运维阶段,提供系统监控、日志查询及针对node服务的进程监控、性能监控及分析,帮助用户快速排查故障、定位问题。

推荐ES知识相关文章

九个超级实用的 ES6 特性

在 Node.js 中 ES Modules 使用入门讲解「实践」

1.5万字概括ES6全部特性(已更新ES2020)

ES5和ES6函数你不知道的区别

从ES6到ES10的新特性万字大总结(不得不收藏)

Node.js要完了吗?

通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events

记好这 24 个 ES6 方法,用来解决实际开发的 JS 问题

手把手教你ES6从设计到实现前端Uploader基础类

ES6 完全使用手册附加案例实战讲解

十分钟上手ES2020新特性

手把手教你ES6版窥探数据结构的世界

消息队列助你成为高薪 Node.js 工程师

「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能

Pug 3.0.0正式发布,不再支持 Node.js 6/8

作者:杨益良 58技术

转发链接:https://mp.weixin.qq.com/s/Y1P2GTj0QMQ0VLJr8FhvZg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值