Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

天猫双11前端分享系列(四):大规模 Node.js 应用 #28

Open
dead-horse opened this issue Nov 30, 2015 · 54 comments
Open

Comments

@dead-horse
Copy link
Member

在刚刚过去的 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. 用户在不同的终端环境下访问 https://1111.tmall.com 这个网址,请求会直接来到 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 和设备类型选择不同的页面返回。返回时设置 varydetector,保证 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 能做的事情也在变化,我们期望它能在之后能在更多的场景下落地。:)

天猫前端团队招聘

如果你看了这篇文章,对加入天猫前端团队有意向的,可以发简历到[email protected],招聘要求见:https://job.alibaba.com/zhaopin/position_detail.htm?positionId=3504

@dllglishaoyi
Copy link

赞得无可救药

@sinoon
Copy link

sinoon commented Nov 30, 2015

个人感觉,牛逼的地方不在于是不是用了node,而是能真的应用node。阿里内部团队提出使用node,也有一段时间了,这次是一次真的实战实装,并且是跨团队的。为居中协调与推进的人点个赞!

@hkongm
Copy link

hkongm commented Nov 30, 2015

不止前端,还有其它牛逼团队的鼎力支持啊!
CDN的detector就不是其它公司说整就能整的。
论前端话语权的重要性。

@hufeng
Copy link

hufeng commented Nov 30, 2015

@yjhjstz
Copy link

yjhjstz commented Nov 30, 2015

怒赞。

@Alan1019
Copy link

66

@looping84
Copy link

前排赞

@KeithZhang
Copy link

速度真是快,赞

@Luckyson
Copy link

666666+

@dagouzhi
Copy link

赞,学习了

@cdll
Copy link

cdll commented Nov 30, 2015

前排学习~

@JanzenZhangChen
Copy link

学习了很多好的思路,谢谢无私的分享

@zysam
Copy link

zysam commented Nov 30, 2015

双 11 对 node 意义不言而喻。

@ghost
Copy link

ghost commented Nov 30, 2015

66666

@ghost
Copy link

ghost commented Nov 30, 2015

请问双11当天的qps高峰能达到多少?跟之前语言比大概提高了多少?

@longtian
Copy link

👍

@dead-horse
Copy link
Member Author

@hongqi 架构不一样,业务不一样,访问量不一样,直接比较 qps 是没有任何意义的。

@FengYuHe
Copy link

6

@ghost
Copy link

ghost commented Nov 30, 2015

@dead-horse 嗯。其实有很多公司不能像天猫这样既有技术又有资源地来推动node做为接入层。很多情况下更关注的是语言切换是否真正地带来收益,包括具体使用多少台服务器,以及使用相同的资源能否扛住更多的qps,甚至系统稳定性等。所以比较好奇的问了下。
当然只是关注这些点显得目光比较短浅没有长远的眼光哈,只是想横向比较一下,使得推动过程中更有说服力一些。

@magicdawn
Copy link

哦, 纯围观~

@jinwyp
Copy link

jinwyp commented Nov 30, 2015

在pc上写的模块 直接就能变成RN 到原生上是怎么做到的?

@yreenchan
Copy link

相当赞

@dead-horse
Copy link
Member Author

@jinwyp 原因是都写了多个版本的,不要想多了。。

@dead-horse
Copy link
Member Author

在去年的时候用 node 替换了老的一个 php 系统,并在天猫首页上经过了去年双十一的验证,当时解决同样的问题,新版(node)的性能是旧版(php)的十倍左右,但是这个性能提升并不代表 node 的性能是 php 的十倍。不过用来说服老板确实是有意义的。 @hongqi

@LingyuCoder
Copy link
Member

666666

@flyyang
Copy link

flyyang commented Nov 30, 2015

@dead-horse 十倍是怎么测出来的。

@dead-horse
Copy link
Member Author

@flyyang 压测以及去年双十一的数据对比。

再次强调,这个数据与语言的关系不大。

@changjie-lin
Copy link

感谢分享!请问 node 的 non-blocking I/O 对与数据库交互的效率影响有多大呢?你们有过对比吗?谢谢 @dead-horse

@yuanzhaohao
Copy link

牛逼啊~wormhole方案确实用着很舒服!

@Kenshinhu
Copy link

wormhole 也能解说一下吗?

@veincheng
Copy link

learn more ..

@wengyulin
Copy link

7666

@skua
Copy link

skua commented Dec 1, 2015

👍

@wellstang
Copy link

6666

@yuanxj1024
Copy link

不仅印证了Node的强大也不断提升着前端的作用力,很赞

@fengzhu1131
Copy link

mark

@pzzrudlf
Copy link

pzzrudlf commented Dec 2, 2015

js和node

@huaxuan
Copy link

huaxuan commented Dec 3, 2015

赞得无与伦比

@kujian
Copy link

kujian commented Dec 3, 2015

mark

@lvtraveler
Copy link

还是太高深了

@murdercdh
Copy link

求一个tiny core的sample

@dingyiming
Copy link

node 的天下呀

@anymost
Copy link

anymost commented Dec 9, 2015

谢谢无私的分享

@iroc
Copy link

iroc commented Dec 11, 2015

多谢分享

@birdxiao
Copy link

对架构方面的东西,毫无拒绝的能力

@qbig
Copy link

qbig commented Dec 23, 2015

感谢分享! "我们只需要所有的模块都有对应的 react native 版本,就可以像搭建 web 的 html 一样搭建渲染出 RN 需要的 js 了!" 这部分有详细些的记载么? 所以天猫的移动端是 native 和RN 比重大概多少@dead-horse

@Dovejun
Copy link

Dovejun commented Jan 27, 2016

感谢分享,找到了前端研究的方向

@unexpectedxx
Copy link

mark

@diydyq
Copy link

diydyq commented Feb 4, 2016

谢谢分享!
以前听过点中途岛方案,看了这篇分享,发现有异曲同工之妙。
CDN,NodeJS,Java EE的Service形成三级缓存,各司其职,依次管理;原来的MVC,现在分离到不同的节点上,分层思想更明确,排错修复独立性也强。(个人观点,有错请不吝赐教)

@juntf
Copy link

juntf commented Jul 2, 2016

感谢分享!

@trent92
Copy link

trent92 commented Mar 3, 2018

运营数据投放平台是怎么做的啊?

@Aaaaaaaty
Copy link

去年看到这篇文章觉得太厉害了,没想到有一天真的可以用上

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests