低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

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

2018 年 12 月 05 日

苏宁的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


2018 年 12 月 05 日 16:494096

评论 3 条评论

发布
用户头像
原来NodeJS这种以IO性能见长的服务器,默认的模板渲染能力还是不如Java,还需要专门优化
2018 年 12 月 08 日 21:44
回复
页面渲染是cpu密集型为主吧?主要是把json数据和一些后台缓存数据转换装配为html文档,树变换操作,启用模板缓存、中间件加载、动态include这些和node没啥关系,关键看web框架的优化成熟度。IO也是指NIO,node和java web server比NIO,这里有个数据https://my.oschina.net/lifeofpi/blog/120210
2018 年 12 月 11 日 19:13
回复
用户头像
我觉得
2018 年 12 月 05 日 21:23
回复
没有更多了
发现更多内容

前端开发:Async/Await的使用

三掌柜

5月日更 5月

在云计算时代,为什么Linux服务器市场占有率如此之高?

读字节

Linux

精选面试题教你应对高级iOS开发面试官(提供底层进阶规划蓝图)

程序员 移动开发 ios开发

作为最好用的可观测平台,如何监控 Grafana

耳东

Grafana Prometheus 5月日更

深度剖析 | 关于数据锁定和读取一致性问题

VoltDB

数据库 数据分析 5G

「学习笔记」《02 | 第一个程序:教你输出彩色的文字》之二

Nydia

学习笔记

如何让消息队列达到最大吞吐量?

Kevin Wan

go 微服务 消息队列 Queue

ThreadLocal不好用?那是你没用对!

王磊

Java 后端 多线程 ThreadLocal 5月日更

预告 · 5月26日IGS大会腾讯云游戏&新文娱分论坛遇见TcaplusDB

tcaplus

数据库 游戏

不忘过去,不畏将来

小天同学

5月日更 汶川地震 不忘过去

户外广告投放的“粗”与“细”

󠀛Ferry

5月日更

声网、新东方、伴鱼英语的音视频技术解读

Jessie

音视频 视频消音

无常中的僵硬与柔软

zhoo299

随笔杂谈 教育 生命 五月日更

怎样做好服务提供方

程序员架构进阶

架构设计原则 服务化 28天写作 5月日更

Python自动打印文件

IT蜗壳-Tango

IT蜗壳教学 5月日更

如何利用k8s拉取私有仓库镜像

Damon

k8s 5月日更 五月日更

Nginx性能分析之gpreftools

运维研习社

nginx 性能分析 5月日更

Dubbo 本地调用

青年IT男

dubbo

【LeetCode】停在原地的方案数Java题解

HQ数字卡

算法 LeetCode 5月日更

Arthas-技术专题-使用指南

李浩宇/Alex

Arthas 五月日更

VMWare中Ubuntu网络配置

进击的梦清

Linux 运维 vmware 网络配置

一文带你读懂PyQt:用Python做出与C++一样的GUI界面应用程序

老猿Python

给Java小白,整理一套能上手的简单编程算法题!!!

小傅哥

Java 程序员 数据结构 算法 小傅哥

Gartner预测2021年全球设备装机量预计将达到62亿台

Geek_bacee5

Gartner 信息技术研究 Gartner预测 全球设备装机量 数据分析研究

华为云官网负责人明哥:我们是如何做到门面不倒,8个月挑战业界翘楚?

华为云开发者社区

JavaScript node.js Serverless 云原生 前端开发

找Matlab代码,看这一篇就够了

攻城先森

matlab 工具分享 5月日更

追寻软件定义的梦想汽车

车骑

自动驾驶 智能汽车 软件定义汽车 汽车制造

MongoDB如何才能优雅且合理地设计?

读字节

mongodb

Gartner预测2021年全球公有云终端用户支出将增长23%

Geek_bacee5

Gartner 信息技术研究 IaaS的市场数据 云服务用户支出 Gartner预测

cri-o 技术探秘2

xumc

最近又有出什么新电影,要不要停泊片刻,与好友相约一起来去看呢?

叶小鍵

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

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