Node.js 在双十一中有哪些应用,表现如何?

如果node.js在双十一中的表现足够亮眼,对国内node.js的发展会有何影响?
关注者
2602
被浏览
55750

20 个回答

文章转载自 天猫双11前端分享系列(四):大规模 Node.js 应用 · Issue #28 · tmallfe/tmallfe.github.io · GitHub ,评论请到 github 上。


----------------- 分割线 -----------------


在刚刚过去的 15 年天猫双十一中,Node.js(后文简称 node) 大放异彩,不仅帮助前端团队快速、高效的解决双十一各个业务上的页面渲染问题,同时在性能和稳定性上也表现非常出色,大大降低了双十一硬件成本的同时,在整个双十一期间未出现任何一起由 node 引发的线上故障。


覆盖业务

天猫内经过一年时间的改造和推进,到 15 年双十一的时候,已经有大量的业务都有了 node 的身影,基本上天猫大部分的 web 页面都是通过 node 渲染出来:

  • 天猫首页、大部分天猫频道页、双十一会场以及所有天猫的活动页面都全部基于 node 应用提供服务。
  • 商品详情、店铺和搜索页等主流程链路上,以及天猫超市和天猫会员等业务线上的页面渲染。
  • 提供给内部运营小二的天猫页面搭建平台 web 层基于 node 进行开发,双十一期间在此平台上搭建了超过 1000+ 个双十一相关活动页面。
工作职责

在上述覆盖了 node 的业务中,node 在其中扮演了多种角色:


完整的 web 应用

天猫页面搭建平台即是一个由 node 负责整个 web 端包括业务逻辑和模板渲染等工作的应用。基于支付宝的 node web 框架 chair,通过 hsf 调用和淘宝共建的页面数据存储的接口,用 node 完成业务逻辑处理、页面渲染和前端接口。


轻量级的模板渲染容器

通过 node 整合前端的天猫组件规范 MUI,开发了一套专注于模板渲染的 node 容器(wormhole),通过这个 node 容器,前端可以专注于展现层的开发,统一前端的本地和线上的代码运行环境,也让后端摆脱了繁琐的套模板工作,专注于提供数据接口。同时这套容器基于天猫的模块化规范,横向打通了各个业务和应用之间的模块共享。

基于这个模板容器,我们完成了商品详情、店铺、搜索页以及超市等业务线上的前后端分离工作,大大提升了前端的开发效率,并有效降低了前后端沟通成本。


页面渲染服务

同样基于天猫前端的组件规范 MUI 和模板渲染的 node 容器,我们完成了一套模块化搭建页面的系统,同时开发并运维了一个用来渲染基于模块搭建的页面的服务,同时这个服务和阿里的 cache CDN 打通,在保证满足业务需求的前提下,降低消耗的计算资源。

基于这个服务,在双十一中提供了 900+ 活动页面的渲染,以及天猫首页和各个频道页的渲染工作,天猫的所有营销引流页面基本都由这个服务提供页面。


进入正题

上面讲了许多我们用 node 做了什么,以及覆盖了那些业务,现在我们来看看,到底我们是怎样用 node 解决实际的业务需求的。

拿这次双十一的会场页举例:

  1. 用户在不同的终端环境下访问 2015双11再见-上天猫,就够了 这个网址,请求会直接来到 CDN 上。
  2. CDN 对用户的终端环境进行判断,并在内存中找到对应终端的缓存文件返回,若未命中缓存,则继续往下执行。
  3. CDN 将请求转发到 node 渲染服务,根据终端类型选择不同的页面响应(pc 页面,h5 页面, react-native 页面)。CDN 响应用户请求,并缓存页面。

在上述流程中,我们看到同一个 url 对应到后端其实是完全不同的页面输出内容,为了达到这个目的,我们和 CDN 团队一起做了许多工作:

  1. 开发了一个 tengine-detector 组件,通过请求的 user-agent 以及约定的一些 cookie 信息,判断用户的终端类型。并部署到 CDN 上,让 CDN 拥有了终端判断的能力。
  2. 用户请求到 CDN 上之后,CDN 会根据用户的终端类型分类,设置一个请求头,例如: detector: pc 表明这个请求的终端设备是 PC 上的浏览器。
  3. 渲染服务获取到这个头之后,根据 url 和设备类型选择不同的页面返回。返回时设置 vary 为detector,保证 CDN 根据不同的设备类型缓存不同页面。

上面提到会根据终端类型对于同一个 url 返回不同的页面,而这些页面其实都是通过一个基于 node 开发的天猫页面搭建平台用模块搭建的。在这个平台上,超过 95% 的模块都拥有 pc 和无线两个版本,本次双十一所有用到的模块都有 react native 的版本。运营只需搭建 PC 上的页面,就会自动生成无线以及 react native 的页面。基于这套方案,我们通过 70+ 高质量的模块,让运营同学完成了超过 900+ 活动页面的搭建。

再深入一点,我们如何来完成这些页面或者是模块的呢?首先,我们希望让前端开发做什么?

  • 编写模板
  • 拿到数据(并处理),和模板进行结合
  • 拿到请求上下文,时间、环境等系统变量来确定不同的展现
  • 管理前端资源和依赖

我们在 xtemplate 模板引擎的基础上进行扩展,让前端通过编写 xtemplate 模板,在 context 中注入一些必需的页面上下文,扩展 xtemplate 的语法,支持引入前端资源。基于这套模板,我们可以在拿到数据后渲染得到完整的页面,基本满足了开发页面在功能上的所有需求。

但是页面中其实有非常多重复性的内容,我们完全可以把他们抽象成一个个的模块,让页面通过模块化的方式来基于模块搭建,在这个过程中我们需要解决几个问题。

  1. 模块版本和静态资源版本的管理:页面可能引用几十个模块,而这些模块依赖的静态资源有重复、有冲突,因此我们会通过一份统一的 seed 来进行依赖版本的管理,每一个模块在发布的时候都会打包好自身的依赖关系,而在将所有的模块组合成页面的时候,将所有模块的依赖表重新进行合并和去重,最终保证页面引用的模块和静态资源唯一。同时我们在模板中通过扩展引入了 FELoader(天猫的静态资源加载器),收集页面的所有静态资源,combo 后插入到页头(css)或者页尾(js)。
  2. 模块如何拿到相应的数据:对于模块而言,他并不需要知道被哪个页面引用了,所有的页面在引用模块的时候需要将模块所需的数据传递进去。而所有的模块开发者需要编写一份模块需要数据的 JSON Schema 描述,通过这份描述文件,搭建平台、投放系统以及其他使用这个模块的人都能够知道要为这个模块产生什么格式的数据。
  3. 配套的搭建平台和数据投放平台来让运营自由组合所有的模块生成页面,并为页面上的每一个模块进行数据投放。

解决完上述问题之后,我们将每一个页面都变成了以下几个部分:

  1. 一份页面的描述文件,声明了这个页面依赖的所有模块,以及渲染这些模块所需的数据的地址。
  2. 一系列相互独立的模块。
  3. 一份包含页面上所有模块需要的数据的数据文件。

最终,我们的渲染服务会根据 URL 和请求的终端环境,找到对应的页面描述文件,请求相应的数据,合并所有的模板渲染成为 HTML 页面。

当我们完成了 web 页面的模块化搭建之后回头再看,是不是 react native(RN) 的页面也能够搭建呢?我们只需要所有的模块都有对应的 react native 版本,就可以像搭建 web 的 html 一样搭建渲染出 RN 需要的 js 了!所以本次双十一使用的所有模块都有 RN 版本,并有多个会场采用了 RN 进行搭建,取得了非常不错的效果,在接下来的双十二中,我们所有的会场都会支持 RN,而这一切对于搭建会场的运营来说都是完全透明的。


稳定性保障

在阿里,所有的双十一相关应用都需要面临的一个大问题就是稳定性,为了保证能够在几亿用户买买买的时候不掉链子,任何一个应用都需要花很大的精力来保障它的稳定性,node 的应用也一样。

对于 node 应用自身而言,我们首先要保证它有充足的测试,通过 mocha + istanbul ,尽可能让测试覆盖每一个功能点和边缘情况。


需要有完善的监控和报警。在阿里内部,我们已经有了内部的监控系统,对于 node 应用而言,只需要按照要求的格式打印的日志,或者通过自己编写日志采集脚本,就可以轻松的搞定监控和报警。

  • 错误日志监控:通过采集脚本采集上来并分类,并设置单机报警和阈值和集群报警的阈值,在异常出现时能够及时发现。
  • 系统状态监控:内存、CPU、load 等的监控,并设置报警阈值,当系统状态异常时能够及时发现。
  • 应用状态监控:QPS、响应时间以及所有的远程调用记录,时刻了解系统的负载和各个依赖节点的服务状态。

同时,对于 node 应用,我们可以使用阿里云团队提供的 alinode ,他们可以提供更多 node 的日志和监控,并提供了在线的 profiler 和快照功能,方便排查线上异常和性能优化。

尽管我们可以对自身的代码做各种测试、各种监控,但是在一个复杂的系统中,各种上下游依赖非常复杂,网络情况也很复杂,这个时候为了保证稳定性,我们还有许多的工作要做。


没有单点

假设一个机房的光缆被挖断了,或者机房所在的城市大规模断电了,然后整个天猫的大部分页面都不能访问了,这明显不能接受,所以我们需要在多个城市的多个机房部署我们的服务。如果存放模板文件或者数据文件的服务挂了怎么办?多个节点,主备读取,同时对所有的文件都加上磁盘文件容灾。对外提供服务的整条链路上的每一个依赖都不能够出现单点问题。


弱化依赖

在排除完单点问题之后,我们再来审视我们的服务,是不是所有的依赖在挂掉后就无法正常服务了?是否我们对于每个依赖异常都有容灾的方案,弱化掉整条链路上的依赖。


预案自动化

对于每一个可能出现问题的环节,我们都需要有针对性的预案,如果这个预案需要人工去执行,就需要思考能否做到自动化。在 node 渲染服务中,可能有各个缓解出问题,链路上的所有预案都要能够自动切换:

  • CDN 回源到多个机房,当某个机房异常时能够通过健康检查自动剔除。
  • 当源站 load 过高时,服务自动切换到静态版本不做渲染。
  • 当模板或者数据的存储节点挂了,通过健康检查自动剔除。
  • ...
总结

再回过头来看看在天猫我们使用 node 做的事情,不一定很牛逼,但是确实是在天猫现在的业务场景下,一个相对较优的使用方案,不论是在解决前端开发效率、还是提升服务质量方面,都发挥了很重要的作用。而经过了这次双十一的考验,我们也认为它已经是一个很成熟的工具,可以帮助我们更好的完成我们的工作。


node 只是工具,在每一个具体的业务场景下都有最合适的使用方法,而随着业务的发展,node 能做的事情也在变化,我们期望它能在之后能在更多的场景下落地。:)

利益相关,负责淘系业务会场支撑系统的架构设计和开发。

一句话概括:你们根本不知道现在大促(包括日常、双十一)是多么依赖Node.js。

(后文用Node、node、nodejs、NodeJs均指Node.js)

Node在阿里内部的当前背景

两年前,你可以说node在阿里内部就像是玩具一样,仅仅被一些了解node前端用在淘系部分业务,进行着“前后端分离”的事情。内部也有一些优秀的node开发者,如淘系代表的苏大师、朴大师,纯技术流代表则有原云OS团队的各种大神。

但是从去年开始,天时地利人和,node在阿里内部已经遍地开花。

从业务划分上来分析:
  • 支撑业务线上产品:包括淘宝、支付宝、1688,有大量系统已经使用node直接面向终端用户
  • 支撑内部日常工作的内部在线系统:各种内部工具系统,这块本来就是适合用node来敏捷开发的
  • 本地开发工具:阿里体系内各BU都有完整的toolchain,尤其是前端团队,用脚趾头想都是用node实现的

从技术架构上来分析,有两种形态:
  • 所谓的“前后端分离”:目前在基础产品线已经比较流行了,未来还会继续推广
  • 全栈应用:目前利用node完成所有业务逻辑的系统在阿里内的确不多,但其原因并不是node不够稳定(后面会继续分析)。但是随着组织架构的进化、对前端岗位职业规划的优化,完全使用node开发的关键应用会越来越多

大促相关

扯了这么多,回到问题本身。只说一个最直接的,大家今年访问到的所有www域页面(包括首页、频道、会场等)全部是一个全栈node应用支撑的。相比以往大促使用的技术方案,已经被证明的优势如下:
  • 节省了巨大的服务器资源
  • 提供页面安全性、稳定性
  • 对业务个性化需求的支持更好

(括号1:具体实现细节只能憋着不说……)
(括号2:评论有问技术细节的。只能简单说。前端技术:以前cdn+php+rsync,现在cdn+node+xtemplate +redis+oss;后端:以前java,现在node+java,本财年内会全部全部node。前端部分以前QPS低的可怕,XSS数量感人,整个体系没人敢去扩展。)

表现?我们之前是出过一次严重故障,后果大家都可以猜到了。但是,正式那次故障,让PE体系和老板们知道了,原来我们的这么多页面都是node支撑的。

大促当天,我们的系统没有出现过任何投诉,来自运营、前端的答疑竟然比日常还少。系统各项指标正常,符合之前的预期。大家最后都是在买买买。

而之前提到的其它node应用,都不同程度上直接或间接的支撑了大促。

node应用对比java应用的表现?

题主的问题,似乎我已经回答完毕了。但是我自己在扩展一下吧。那些质疑node的人,也多半会不由自主的把node和java进行对比。

目前java仍然是阿里的根基,基础产品线(交易、detail、购物车等)目前看不到迁移到别的语言的可能。因为实在太稳定了,相关的容灾方案也跑了这么多年。没有明显的收益,人家为何要换技术?

从已经官方公布的本次支付数据来看,峰值8.59万每秒。位于上游的应用,是什么数字?我这里只能憋着不能讲。面对如此巨大的TPS,不是说JVM多牛逼就可以解决的。这里主要有三方面:

  • 基础设施:应用监控与日志、流量分配、流量降级、企业级中间件等,都需要语言框架级别的配套设施,这些node都没有。虽然朴大师主导的alinode已经开始beta了,虽然内部也有一些node中间团队(例如支付宝的苏千大师出品的各种东西),但和java比起来,还相差甚远。
  • 生态促进:这是比第一条更要命的。如果说稳定业务已经长期用java,不更换技术是正常的。那么新业务的开发,大家发现上下游全是java应用,那么就开始纠结自己为何要不走寻常路了。现在阿里内不的全栈node业务都没有关联性,不如java应用拥有如此强大的关系网。这一点也决定了,这个java开发即使转岗,也是使用的同一套技术和框架,对接类似的配套业务。
  • 人才储备:java发展了多年,有众多的研究员级别的大神为java体系撑腰,并直接参与java和jvm的开发。反观node体系,阿里内部并无一个能全方位托底之人(考虑复杂架构设计、性能与稳定性分析、运维等各角度)。node本身的contributor名单中,目前也还为有阿里的人(据说马上有)。

这些差距,毫不夸张的说,需要5年甚至10年的追赶。就现在的状况,就算老板让我去用node重写一些交易业务,我也不敢去做。

所以,目前核心的交易链路,是没有任何全栈node应用的。node在这块的表现自然没法评价。硬要评价,也是“无表现”。

总结

node的应用场景在阿里内部还没有完全铺开。node社区本身已经进入了指数期,剩下的是我们node开发在自己企业内部进行落地。

但是在其已经应用的领域,其表现是非常好的。

PS
最后软文一把,希望对node感兴趣的Javascript开发、C/C++、Java开发加入我们团队,探索node在淘系业务的未来。
咨询邮箱: long.qul@alibaba-inc.com
团队博客:Taobao FED | 淘宝前端团队
为什么?