一、前言

在后面几篇文章中,置信大家对vivo官网商城的前端架构演变有了肯定的理解,从稳步推动前后端拆散到小程序多端摸索实际,团队不断创新尝试。

在本文中,咱们来分享一下vivo官网商城在Node 服务端渲染(Server Side Rendering, SSR)方面的实战经验。本文次要围绕以下几个方面进行论述:

  • CSR与SSR的比照
  • 性能优化
  • 自动化部署
  • 容灾、降级
  • 日志、监控

二、背景

vivo官网商城目前前后端拆散采纳的是SPA单页模式,SPA会把所有 JS 整体打包,无奈漠视的问题就是文件太大,导致渲染前期待很长时间。特地是网速差的时候,让用户期待白屏完结并非一个很好的体验。因而 vivo 官网商城前端团队尝试引入了SSR技术,以此来放慢页面首屏的访问速度,从而晋升用户体验。

三、SSR简介

3.1 什么是SSR?

页面渲染次要分为客户端渲染(Client Side Render)和服务端渲染(Server Side Rendering):

  • 客户端渲染(CSR)

服务端只返回一个根本的html模板,浏览器依据html内容去加载js,获取数据,渲染出页面内容;

  • 服务端渲染(SSR)

页面的内容是在服务端渲染实现,返回到浏览器间接展现。

3.2 为什么要应用SSR?

与传统 SPA (单页应用程序 (Single-Page Application)) 相比,SSR的劣势次要在于:

  • 更好的搜索引擎优化(SEO),SPA应用程序初始展现loading菊花图,而后通过Ajax获取内容,搜索引擎并不会期待异步实现后再行抓取页面内容;
  • 更快的内容达到工夫 (time-to-content),特地是对于迟缓的网络状况或运行迟缓的设施,无需期待所有的JavaScript都实现下载并执行,才显示服务器渲染的标记,用户可能更疾速地看到残缺渲染的页面,晋升用户体验。下图可能更直观的反馈加载时成果。

CSR和SSR页面渲染比照:

四、SSR 实际

vivo官网商城我的项目的技术栈是Vue, 思考到从头搭建一套服务端渲染的利用比较复杂,所以抉择了Vue官网举荐的Nuxt.js框架,这是基于 Vue 生态的更高层的框架,为开发服务端渲染的 Vue 利用提供了极其便当的开发体验。

这里不做根底应用的分享,有趣味的同学能够到Nuxt.js官网学习根底用法;咱们次要聚焦于在整个实际过程中,次要遇到的一些挑战:

  • 性能:如何进行性能优化,晋升QPS,节约服务器资源?
  • 容灾:如何做好容灾解决,实现主动降级?
  • 日志:如何接入日志,不便问题定位?
  • 监控:如何对Node服务进行监控?
  • 部署:如何买通公司CI/CD流程,实现自动化部署?

4.1 性能优化

尽管Vue SSR渲染速度曾经很快,然而因为创立组件实例和虚构DOM节点的开销,与基于字符串拼接的模板引擎的性能相差很大,在高并发状况下,服务器响应会变慢,极大的影响用户体验,因而必须进行性能优化。

4.1.1 计划1 启用缓存

a、页面缓存: 在创立render实例时利用LRU-Cache来缓存渲染好的html,当再有申请拜访该页面时,间接将缓存中的html字符串返回。

nuxt.config.js减少配置:

serverMiddleware: ["~/serverMiddleware/pageCache.js"]

根目录创立serverMiddleware/pageCache.js

b、组件缓存: 将渲染后的组件DOM存入缓存,定时刷新,有效期内取缓存中DOM。次要实用于重复使用的组件,多用于列表,例如商品列表。

配置文件nuxt.config.js:

const LRU = require('lru-cache')module.exports = {  render: {    bundleRenderer: {      cache: LRU({        max: 1000,                   // 最大的缓存个数        maxAge: 1000 * 60 * 5        // 缓存5分钟      })    }  }}

缓存组件减少name及serverCacheKey作为惟一键值:

export default {     name: 'productList',     props: ['productId'],     serverCacheKey: props => props.productId}

c、API缓存: Node服务器须要先调用后盾接口,获取到数据,而后能力进行渲染,获取接口速度的快慢,间接影响到渲染的工夫,对接口的缓存能够放慢每个申请的处理速度,更快地开释掉申请,从而进步性能。API缓存次要实用于数据根本放弃不变,变更不是很频繁,与用户集体数据无关的接口。

4.1.2 计划2 接口并发申请

同一个页面,在Node层可能会同时调用多个接口,如果是串行调用,须要期待的工夫会比拟长,如果是并发申请,会放大等待时间。

例如:

let data1 = await $axios.get('接口1')let data2 = await $axios.get('接口2')let data3 = await $axios.get('接口3')

能够改成:

let {data1,data2,data3} = await Promise.all([    $axios.get('接口1'),    $axios.get('接口2'),    $axios.get('接口3')])

4.1.3 计划3 首屏最小化

影响用户体验次要是首屏的白屏工夫,而第二屏、第三屏...,并不需要立刻显示。以商品详情页为例,如下图:

能够对页面构造进行拆分,首屏元素采纳SSR,非首屏元素通过CSR;SSR数据须要通过asyncData办法来获取,CSR数据能够在mounted中获取。

CSR写法如下:

<client-only>    客户端渲染dom</client-only>

4.1.4 计划4 局部页面采纳CSR

并不是所有页面对体验、SEO要求都很高,像商城这样的业务,能够只对首页、商品详情页等外围页面做SSR,这样能够大大减少服务端的压力。

4.1.5 优化前后性能压测比照

优化前:

优化后:

从上图能够看出,未经优化前QPS只有125,通过一系列优化QPS达到了6000,晋升了靠近 50倍。

这里的降级是指将SSR降级为CSR,应用Node做SSR,瓶颈在于CPU和内存,在高并发状况下,很容易导致CPU飙升,用户拜访页面工夫变长,如果Node服务器挂了,间接会导致页面拜访不了。所以为了保障我的项目上线之后安稳运行,须要提供容灾、降级计划。

Nuxt.js能够同时反对CSR和SSR,咱们在打包时,既生成SSR的包,同时生成CSR的包,别离进行部署。

我的项目中采纳了以下几种降级计划:

4.2 降级策略

4.2.1 监控零碎降级

Node服务器上启动一个服务,用来监测Node过程的CPU和内存使用率,设定一个阈值,当达到这个阈值时,进行SSR,间接将CSR的入口文件index.html返回,实现降级。

4.2.2 Nginx降级策略

4.2.2.1全平台降级

例如618,双11等大促期间,咱们当时晓得流量会很大,能够提前通过批改Nginx配置,将申请转发到动态服务器,返回index.html,切换到CSR。

4.2.2.2单次访问降级

当偶发性的Node服务器返回5xx错误码,或者Node服务器间接挂了,咱们能够通过如下Nginx配置,做到主动切换到CSR,保障用户能失常拜访。

Nginx配置如下:

  location / {      proxy_pass Node服务器地址;      proxy_intercept_errors on;      error_page 408 500 501 502 503 504 =200 @spa_page;    }  location @spa_page {      rewrite ^/*  /spa/200.html break;      proxy_pass  动态服务器;  }

4.2.2.3指定渲染形式

在url中减少参数isCsr=true,Nginx层对参数isCsr进行拦挡,如果带上该参数,指向CSR,否则指向SSR;这样就能够通过url参数配置来进行页面分流,加重Node服务器压力。

4.3 CI/CD 自动化部署

基于公司的CI/CD,咱们实现了Docker部署和Shell脚本部署两种自动化部署计划。

4.3.1 计划1 Shell脚本构建、部署

对于Shell脚本的形式,咱们次要解决的问题是如何通过脚本来装置指定Node的版本,这里咱们能够分为两步:

1、装置nvm, nvm 是Node.js 的版本管理器(version manager)2、通过nvm装置或者切换成对于的Node版本
# 定义装置nvm的办法install_nvm() {  echo "env $app_env install nvm ..."  wget --header='Authorization:Basic dml2b2Rldm9wczp4TFFidmtMbW9ZKn4x' -nv -P .nvm http://xxx/download/nvm-master.zip  unzip -qo .nvm/nvm-master.zip  mv nvm-master/* $NVM_DIR  rm -rf .nvm  rm -rf nvm-master  . "$NVM_DIR/nvm.sh"  if [[ $? = 1 ]];  then    echo "install nvm fail"  else    echo "install nvm success"  fi}
# 定义装置Node的办法install_node() {   # command_args为用户自定义的Node版本号  local USE_NODEVER=$command_args  echo "will install NodeJs $USE_NODEVER"  nvm install $USE_NODEVER >/dev/null  echo "success change to NodeJs version" $(node -v)}
# Node环境装置prepare() {   if [[ -s "$NVM_DIR/nvm.sh" ]];  then    . "$NVM_DIR/nvm.sh"  else    install_nvm  fi  echo "nvm version $(nvm --version)"  install_node}

4.3.2 计划2 Docker构建、部署

Docker是一个开源的利用容器引擎,让开发者能够打包他们的利用以及依赖包到一个可移植的镜像中,而后公布到任何风行的 Linux或Windows 机器上,也能够实现虚拟化。容器是齐全应用沙箱机制,相互之间不会有任何接口。

# 根底镜像FROM node:12.16.0# 创立文件寄存目录RUN mkdir -p /home/docker-demoWORKDIR /home/docker-demoCOPY . /home/docker-demo# 装置依赖RUN yarn install# 打包,并把动态资源进行md5压缩RUN yarn prod# 动态资源部署CDNRUN yarn deploy# 端口号EXPOSE 3000# 我的项目启动命令CMD npm start

相比较而言,Docker部署具备很大劣势:

  • 构建、部署更加不便
  • 统一的运行环境「这段代码在我机器上没问题啊」
  • 弹性伸缩
  • 更高效的利用系统资源
  • 快 \- 治理操作(启动,进行,开始,重启等)都是以秒或毫秒为单位

4.4 监控、告警

监控是整个产品生命周期中十分重要的一环,事先及时预警发现故障,预先提供详实的数据用于追究定位问题。
在利用呈现故障时,须要有适合的工具链来撑持问题的定位修复,咱们引入了开源的企业级 Node.js 利用性能监控与线上故障定位解决方案Easy-Monitor,能够更好地监控 Node.js 利用状态,来面对性能和稳定性方面的挑战。咱们在内网部署了这套零碎,并进行了二次开发,集成了内网域登录,并能够通过外部聊天工具推送告警信息。

 

4.5 日志

利用上线后,一旦产生异样,第一件事件就是要弄清过后产生了什么,比方用户过后如何操作、数据如何响应等,此时日志信息就给咱们提供了第一手材料。因而咱们须要接入公司的日志零碎。

4.5.1 实现

日志组件基于log4js封装,对接公司的日志核心

在nuxt.config.js中减少:

export default {  // ...  modules: [      "@vivo/nuxt-vivo-logger"  ],  vivoLog: {      logPath:process.env.NODE_ENV === "dev"?"./logs":"/data/logs/",      logName:'aa.log'  }}

4.5.2 应用

async asyncData({ $axios,$vivoLog }) {    try {      const resData =  await $axios.$get('/api/aaa')      if (process.server) $vivoLog.info(resData)    } catch (e) {      if (process.server) $vivoLog.error(e)    }},

4.5.3 后果

五、写在结尾

用户体验的晋升是一个永恒的话题,vivo官网商城前端团队始终致力于技术的不断创新,心愿能通过技术的摸索给用户带来更好的体验;以上是vivo官网商城前端团队在SSR技术方面实际的一些教训,分享进去心愿能和大家一起学习、探讨。

  • vivo 商城前端架构降级—多端对立摸索、实际与瞻望篇
  • vivo 商城前端架构降级—前后端拆散篇
  • vivo商城前端架构降级-总览篇
  • vivo 寰球商城:从 0 到 1 代销业务的交融之路
  • vivo 寰球商城:架构演进之路

作者:vivo 官网商城前端团队