苏宁的Node.js实践:不低于Java的渲染性能、安全稳定迭代快

前端 Node.js 的使用场景大多集中在前端工具上,当前的前端主要把它定位为辅助。苏宁易购使用 Node.js 作为前后端分离的主要手段,经历了从技术引进到全面开花,从边缘功能到核心业务,从纷乱到稳定的过程。同时 Node.js 作为新引入的技术,与公司原有架构融合衔接面临着怎样的挑战?以下是苏宁技术总监 禹立彬老师在 7 月深圳 ArchSummit 全球架构师峰会上的演讲整理。

在苏宁引入 Node.js 之前,苏宁已经有了成熟的技术架构。

\"\"

苏宁的技术架构,由苏宁云、基础支撑、后台、中台和前台组成。苏宁云主要为业务开发提供云服务。基础支撑,包括数据连接协议、防火墙、日志、中间件、短信等。在苏宁云和基础支撑之上,业务开发分为前中后台。而 Web 前端,主要集中在前台上。包含 PC 端、移动 WAP 端等。

Node.js 的应用非常广泛,在不同的公司,可以用作微服务,也可以用来提供 API,苏宁引入 Node.js,最主要的,是用 Node.js 做中间层,当做一个 Web 渲染器,渲染页面,来实现前后端分离。

Web 前台系统

\"\"

在前台系统里,以前的开发模式,完全是 Java 技术栈。Java 系统,分为 Java Service 服务器,和 Java Web 服务器,Java WEB 服务器读取 Java Service 服务器提供的接口,通过 FTL 模板来渲染页面。

\"\"

引入了 Node.js 以后,苏宁研发团队的目标是使用 Node.js 替代 Java Web 服务器的渲染位置,使用 Node 模板,去替换 Java 模板,去除了模板文件谁写这样的模糊地带,让后端的 Java 工程师,只写 JSON 服务,实现前后端分离。

在应用前后端分离后,显式的获得了一些好处,Node.js 系统的迭代速度优势明显强于 Java Web,包括由于 Node.js 的轻量,带来的快速开发快速迭代,以及减少了前后端沟通上的“联调”时间成本,加快了项目的开发速度。同时,减少老项目里 Java 后台工程师写页面导致的一些 BUG,提高了代码质量。

由于以上的这些优点,现在苏宁易购的 Node.js 项目越来越多,逐渐深入到核心业务。最早期,苏宁只是在用户体验收集这样的边缘页面使用 Node.js,现在已经在海外购,小程序,大聚惠,我的易购,香港站,购物车等业务中都广泛的使用了 Node.js,这样就不可避免的直面更多的技术挑战。

Node.js 如何融入已有技术架构

当只是作为边缘业务时,Node.js 项目尚可以通过一些临时方案,或者引入试点,来逃避,但是深入核心业务后,Node.js 项目很快,就会被纳入总的技术架构里。

\"\"

这是一张比较简单的 Node.js 应用部署图。一个 Node.js 应用被访问时,会使用公共的负载均衡,使用应用防火墙,当达到 Node 服务器时,要使用物理机和虚拟机,Node 服务器要访问 Java Service 服务器也需要连接协议

\"\"

最简单的是 IaaS,在这个层级上,Node 可以完全可以复用苏宁云成熟的网络,存储,物理机,虚拟机等资源。

\"\"

到了虚拟机这个层级,在这幅 Node.js 服务器图上,可以看到单台 Node 服务器,有一个 Nginx,来做访问的 accessLog 和做反向代理到本机的 Node.js 应用端口,这台机器上同时安装了 PM2,来启动多个 Node 应用,对应不同的端口,来提供对外服务。

\"\"

在 PaaS 这个层级上,苏宁也尽量沿用了公司已有的技术资源。比如在操作系统方面,使用了 Linux,尽量向已有技术架构靠拢。

在服务器的 Node.js 版本上,在去年年初的版本是 Node 6.9,去年年底已经将 Node 版本升级到 Node 8 了,研发团队坚持使用 LTS 版本的 Node.js。到 Node 有大版本更新时,同时更新 PaaS 平台的 Node 版本。

在 Nginx 上,选择的也是已有的通用 Nginx 版本,Node 服务器对 Nginx 版本要求不严格,Nginx 监听多域名的 80 端口后,反向代理到 Node 端口就好。

Redis 的情况要麻烦一些,Node.js 由于进程的原因,遇到 Session 这样需要多进程或者多服务器直接共享数据时,就必须借助 Redis。很显然,Java 体系内,并没有对应的 Node 版本的 Redis 客户端,于是苏宁自己编写了一个基于 ioredis 的 Redis 客户端,来满足需求。

在 DB 上,苏宁则遵循总的技术架构要求,Node 服务器不直连 DB,要获取数据时,永远是连接 Java 服务。

监控报警

解决了服务器环境后,Node 也要接入日志服务和报警系统。通过配置 Nginx 日志格式和 PM2 的日志插件 pm2-logrotate 来将日志格式符合总技术架构的日志平台要求,并在日志平台上配置 4XX 和 5XX 报警,并且针对 Node 本身的一些特色,编写 PM2 插件,监控 Node 进程异常,并发送异常到苏宁内部的即时通信团建上。

CI/CD 发布系统

服务器好了,代码编写好了,也需要发布。利用公司的统一发布平台,在平台上新建了 Node.js 标准发布,统一了 Node 代码包打包方案,统一了代码部署目录,统一从内部私库安装 NPM 包,统一了应用重启的方法。

\"\"

除此之外,为了满足公司的总技术架构要求,苏宁研发团队还编写了基于 Node 的调用链监控组件,可以适配 ESB/RSF 通信协议的客户端组件,以及适合 Varnish 下的 KOA,EXPRESS 中间件。

技术挑战

解决了技术架构要求方面的问题,Node 可以正规军上岗了,核心业务又会带来更高的技术要求。

以大聚惠页面为例,大聚惠是苏宁的一项营销业务,很多优惠活动,是通过大聚惠的名义放出的,因此业务非常重要。又因为运营需要,总是在凌晨 0 点,货品上新,要求此时页面不能有缓存,而且由于电商业务的特殊性,会遇到 618,818,双十一这种半夜抢购的情况,因此全靠服务器硬扛流量洪峰,这就对应用性能,提出了很高的要求。

这个项目上线的时候,恰好是升级了 Node 8,研发团队把框架从 express 转换为 KOA,写了一样的代码,压测时,4C4G 单机才 40TPS,而同样的 Java 系统,单机约为 200TPS,性能差距明显。

并发性能优化之路

首先考虑是缓存问题,经过排查,在 KOA 下,并不会默认开启,模板缓存,导致每次总是去硬盘读模板,当然快不了。果断优化,TPS 上升为 120TPS,依然差距明显。Express 框架中会默认开启模板缓存,而默认的 KOA2 并不会开启,首先开启模板缓存性能提升明显。

另外,通过 CPU-PROFILER 排查,发现路由消耗的时间挺多,匹配字符串路由,和匹配正则路由,时间消耗差距明显,于是将路由排序,优先选择字符串路由,将 TPS 推向 140TPS。

再查,为了减少并发,除渲染模板外,Node 还在业务里,合并了静态资源地址,并且中间件加载的策略也可以优化,去除掉一些可以不用的中间件。比如只用 EJS 模板,那么就去除其他模板引擎的支持,通过这些优化,讲 TPS 提升到了 180TPS。

TPS 没有提升后,再排查,发现 include 函数执行时间很长,发现 ejs 源码处理 include 时,总是去硬盘里查找是否有被 include 的模板文件,而这个页面是多人开发,include 使用非常频繁,再进一步优化,终于达到了 220TPS。

不低于 Java 的渲染性能

最后,获得了不低于 Java 的渲染性能。很多文章博客对待 Node 渲染页面时会两级分化,一极认为 Node 不适合做这种 CPU 密集型操作,另一极就是不断宣扬 Node 性能强劲,但是在苏宁实际的应用中,从来没想过超过 Java 多少倍的性能,事实上也是。Node 的基础性能略高于或者持平于老的 Java FTL 渲染器。

安全与稳定

除了性能,安全与稳定也是重点需要的环节。针对 Node.js 来说,客观的说,安全文档方面是不如 Java 等语言的。

一方面是最后后来者,追赶前辈需要时间,另一方面也是 Node.js 的固有问题。Node.js 是单线程的,代码报错会导致进程退出,在 Node 生态早期,会直接导致 Node 访问挂掉;

第二个,JS 是弱类型语言,很多人认为弱类型的语言写的没有安全感,没有代码检查;

第三个,NPM 很好,开源社区很强大,组件很多很方便,但是对于企业用户来说,都抵不过一个 left-pad 事件,公网的 NPM 包也会良莠不齐,如果出现了安全漏洞,影响就会非常大。

问题如何解决

NPM 包策略。苏宁使用公司的私有 NPM 仓库来安装 NPM 包,避免外网扰动,导致无法安装问题。在核心业务中,限制使用不流行的 NPM 包,减少风险。在 package.json 里的包版本,使用确定的版本,不用符号,减少包升级导致的 bug。对于自己开发的 NPM 包,严格进行单元测试及安全测试,进一步的减少风险。

使用 PM2。针对 Node 进程挂掉的问题,苏宁使用了留下的 PM2,来保证 Node 进程的存活。当 Node 进程挂掉时,PM2 会重启他们。感谢 PM2,通过它,也实现了发布的无缝重启,保证了平滑升级。

Node.js 系统的相对安全

安全上,苏宁强制了所有的 Node 系统加入应用防火墙 WAF,使用基于 KOA 的安全中间件 XSS,尽量使用精确匹配的路由,减少注入。并在上线前,做完全的安全测试,实现 Node 系统的相对安全。

前端团队的挑战

\"\"

另一方面,由于引入了 Node,前端工程师对 Node 相关的知识了解较少,也会犯一些低级错误,技术挑战也是非常大的,知识要求被增加了很多。

为了解决这个问题,苏宁成立了专门的前端架构组,为各业务团队保驾护航。在发布,配置,安全监测等各个方面帮助业务开发团队。

全栈技能提升计划

\"\"

并在工作中,加强 Node 技能培训。梳理出容易犯的低级错误,比如 promise 不写 catch,某个条件分支里,不写请求返回,通过宣讲的方式,提高代码质量,并组织代码评审等活动,进一步的提升技术能力。

Node.js 的影响

可以说,进入了核心业务,前端团队遇到的挑战是越来越大的,同时,Node 的推进也带来了一些正面负面的影响,时间有限,不做太多的讲解,仅举几个方面。

第一个方面,项目更敏捷了,Node.js 发布不涉及后台服务,即使发布出了小问题,也可以快速再次发布和回滚,因为 Node.js 系统其实是可以 24 小时发布,对业务支撑显然更迅速敏捷。运营商务。都显然的欢迎 Node。

同时,Node 的引入,也对前端团队带来了影响。Node 的引入带来了前端工作量的增加,需要更多的前端工程师投入。

另一方面,也显著的提高了团队的技术活力,在团队内部刮起了全栈风,技术更活跃,解决问题的方案也更多了。

最后还有一些小型的负面影响,定位 bug 时,时间有所增加。需要查 Node 的问题,还是 Java 的问题;另一方面,访问性能因为 HTTP 的问题,略微增加了几毫秒。当然这对于前面的好处来讲都是可以接受的。

嘉宾介绍

禹立彬,苏宁技术总监,十年 Web 前端开发经历,中国最早一批前端开发者,历任西祠胡同前端负责人,途牛旅游网前端架构师等职务。现任苏宁消费者平台研发中心前端技术总监,负责苏宁易购网站前端领域的技术管理工作。在基于 Node.js 的前后端分离,ReactNative/Weex 开发上有丰富的技术实践经历。

12 月 7 日北京 ArchSummit 全球架构师峰会上,来自美团、百度、阿里、快手的讲师齐聚一堂,共同分享“打造 Native 体验 Hybrid App 实践”、“定制统一可维护的前端架构”、“10 年双十一前端关键技术”和“同构 Web App 的另一种探索”的分享。 https://bj2018.archsummit.com/schedule

购票联系票务灰灰 17326843116

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MVP群聊某美国公司的应聘试题(压死九个还是一个)

某美国公司的应聘试题(压死九个还是一个),测试你的管理方式有二条铁轨,一条新的,一条旧的。有了新铁轨后,旧铁轨不再有火车通过。有一天有十个小孩到铁轨上玩耍,九个小孩在新铁轨上玩&#xff0…

html与cgi脚本的配合使用

利用boa服务器测试arm开发板上的cgi和html联合编程的小例程。很简单,但是当时觉得很有意思。在这里给大家展示一下,高手飘过。 在ubuntu下安装boa测试环境,即先在本地搭建一个boa的网页服务器。apt-get install boa。稍作配置即可。我的Boa按…

zabbix3监控ESXI主机

ESXI主机VMware公司企业级虚拟化的解决方案Vsphere的重要组件,也是虚拟机的宿主机,对其监控有着重要的意义,下边介绍二种方发对其监控。 方法一:通过修改服务端的控制项来进行监控。 虚拟机监控分两个步骤完成。首先,Z…

mybatis jar包_springboot2整合mybatis-plus3踩到的坑

前言最近在进行项目重构,在架构师的建议下,就把项目中mybatis切换成mybatis-plus。因为mybatis-plus在mybatis的基础上只做增强不做改变,因此切换的成本很低,就只需改jar和配置内容,原先的代码无需改动。因为mybatis-p…

共享几套silverlight2 toolkit最新的皮肤控件样式下载

下载了最新的silverlight2 toolkit看看,发现里面的控件样式还是多漂亮的,与大家分享下。 blue dark light orange purple red 样式源码下载:点击下载 当然,我最喜欢的还是orange哦。 转载于:https://www.cnblogs.com/liaohenchen/…

开会=浪费时间?阿里技术团队这样开项目复盘会

2019独角兽企业重金招聘Python工程师标准>>> 阿里妹导读:复盘是项目结束后必不可少的阶段,好的复盘会议能够有效地促进团队成长。今天,阿里项目管理专家鹿迦以自身的经验,为大家分享如何做好一个项目的复盘。这篇文章分…

Extjs中使用FusionChart举例

一 前言: 在项目实施中,设计统计部分经常会使用图表进行显示,在Extjs3中内置了图表控件,但实际表现无法达到3D的美观效果,通过查找FusionChart可以实现比较美观的3D或2D图表显示。注:FusionChart是个商业…

drawitem设置指定行的背景颜色_Java 为 Excel 中的行设置交替背景色

点击上方 好好学java ,选择 星标 公众号重磅资讯、干货,第一时间送达今日推荐:牛人 20000 字的 Spring Cloud 总结,太硬核了~作者:Jazzz链接:https://www.cnblogs.com/jazz-z/p/12665819.html在制作Excel表…

常见的关系型数据库和非关系型数据及其区别

一、关系型数据库 关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织 优点:1、易于维护:都是使用表结构,格式一致;2、使用方便:SQL语言通用,可用于复杂查询&#x…

无法检查指定的位置是否位于cfs上_(干货分享)一文搞明白 节气门位置传感器的作用、故障类型与症状、诊断方法...

1 位置节气门位置传感器(ThrottlePositionSensor,TPS),位于节气门体上,其安装形式因节气门结构的不同而有所差异:对于传统的机械拉索式节气门,节气门位置传感器通常以一个独立元件的形式安装在节气门体的侧面&#xf…

Asp.net(C#)-显示所有缓存 清除所有缓存

//清除所有缓存protectedvoidRemoveAllCache() { System.Web.Caching.Cache _cache HttpRuntime.Cache; IDictionaryEnumerator CacheEnum _cache.GetEnumerator(); ArrayList al new ArrayList(); while (CacheEnum.MoveNext()) { …

Python--day60--一个简单(不完整)的web框架

转载于:https://www.cnblogs.com/xudj/p/10091775.html

activemq 发两条只收到一条_浅谈ActiveMQ与使用

更多大数据架构、实战经验,欢迎关注【大数据每日哔哔】,期待与你一起成长!本文将介绍一下 ActiveMQ 的安装、原理和简单实战。一、什么是消息中间件消息中间件顾名思义实现的就是在两个系统或两个客户端之间进行消息传送二、什么是ActiveMQAc…

ZZ:深入理解new

new的过程当我们使用关键字new在堆上动态创建一个对象时,它实际上做了三件事:获得一块内存空间、调用构造函数、返回正确的指针。当然,如果我们创建的是简单类型的变量,那么第二步会被省略。假如我们定义了如下一个类A&#xff1a…

大数据小白系列——HDFS(1)

【注1:结尾有大福利!】 【注2:想写一个大数据小白系列,介绍大数据生态系统中的主要成员,理解其原理,明白其用途,万一有用呢,对不对。】 大数据是什么?抛开那些高大上但笼…

html select选择事件_一道搜狗面试题:IO多路复用中select、poll、epoll之间的区别...

(1)select>时间复杂度O(n)它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们…

delphi tclientsocket接收不到返回数据_RS—485中教你主站发送报文结构、从站返回报文结构?系列11...

作者:马乐1.主站发送报文结构大家可以看到我之前写的文章中的程序都是没有什么具体功能的,都是两个站点之间互相传递数据,这些数据我们只是看看是否可以正常接收发送,数据本身是没有任何含义的。很明显在实际使用过程中我们是不会…

MybatisPlus 通用枚举无法正确取值

正常使用mybatisplus <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.4</version></dependency> 使用后发现项目中原先对枚举值的转换存在异常&#xff1a; ER…

python input 文件名_Python播放音频与录音

这一讲主要介绍些音频基本处理方式&#xff0c;为接下来的语音识别打基础。三种播放音频的方式使用 python 播放音频有以下几种方式&#xff1a;os.system()os.system(file) 调用系统应用来打开文件&#xff0c;file 可为图片或者音频文件。缺点&#xff1a;要打开具体的应用&a…

ActionScript 3.0 Step By Step系列(四):来自面向对象开发之前的呐喊:“学会写可重用的代码”...

增强代码的可重用能力&#xff0c;从创建可重用的代码开始&#xff0c;可重用的代码则是通过从现有代码中重构加以封装,使其成为功能单一的可复用代码块。这句话笼统点说便是“封装”或“抽象”。 在实际的编程开发中&#xff0c;要实现代码重用&#xff0c;而不是每次都去Copy…