Nuxt ssr如何做性能优化
Nuxt的背景
Nuxt.js 是一个基于 Vue.js 的通用应用框架。
通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI 渲染。
我们的目标是创建一个灵活的应用框架,你可以基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js。
Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置。
除此之外,我们还提供了一种命令叫:nuxt generate ,为基于 Vue.js 的应用提供生成对应的静态站点的功能。
我们相信这个命令所提供的功能,是向开发集成各种微服务(Microservices)的 Web 应用迈开的新一步。
作为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等。
Nuxt 特性
- 基于 Vue.js
- 自动代码分层
- 服务端渲染
- 强大的路由功能,支持异步数据
- 静态文件服务
- ES2015+ 语法支持
- 打包和压缩 JS 和 CSS
- HTML 头部标签管理
- 本地开发支持热加载
- 集成 ESLint
- 支持各种样式预处理器: SASS、LESS、 Stylus 等等
- 支持 HTTP/2 推送
Lifecycle
Nuxt 直出原理
nuxt直出本质,其实还是vue在服务端的模板渲染,依然会涉及到 vue-component -> ast -> render(vdom)。对 compile 熟悉的同学知道,在 ast 的 parse 阶段,会做大量的正则匹配,属于CPU密集操作。并且为了隔离请求不同的请求,它会为每一个请求创建一个上下文 context ,这样一来,vue ssr 和传统的模板引擎相比,其性能相差甚远。
那如何优化?
SSR的优化策略一:缓存
- 缓存
-
- 组件级别缓存
-
- 数据级别缓存
-
- 页面级别缓存
组件级别缓存
nuxt的组件级别缓存,使用 Component Cache module。使用的缓存策略还是LRU Cache
{
modules: [
'@nuxtjs/component-cache',
[
'@nuxtjs/component-cache',
{
max: 10000,
maxAge: 1000 * 60 * 60
}
]
]
}
在需要缓存的组件中使用 serverCacheKey 函数来标识
export default {
name: 'ReplyItem',
serverCacheKey: props => props.postId,
props: {
postId: String
}
}
数据级别缓存
对那些不涉及用户信息和实时性要求不高的接口进行缓存。对于数据层的缓存,依然可以使用LRU Cache
页面缓存
非千人前面的页面,可以对整个页面进行缓存。可以在 middleware 里处理
middleware/pageCache.js
const LRU = require('lru-cache')
const options = {
max: 1000,
maxAge: 1000 * 60 * 5
}
// 需要进行页面级别缓存的路由
const CACHE_URL = ['/xxx', '/xxx', '/xxx']
const cache = new LRU(options)
export default function (req, res, next) {
const url = req._parsedOriginalUrl
const pathname = !!url.pathname ? url.pathname : ''
if (CACHE_URL.includes(pathname)) {
const existsHtml = cache.get(pathname)
if (existsHtml) {
// 不要忘了设置 Content-Type 不然浏览器有时候可能不会渲染而是触发下载文件
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
return res.end(existsHtml.html, 'utf-8')
} else {
res.original_end = res.end
res.end = function (data) {
if (res.statusCode === 200) {
cache.set(pathname, { html: data })
}
res.original_end(data, 'utf-8')
}
}
}
next()
}
之后加到nuxt.config.js 的中间件中即可
SSR的优化策略二:业务后移
其实就是最小屏优化,实际就是讲SEO权重底的模块后移到client端处理。参考 movie.xunlei.com 的实践。
但影评在做最小屏优化后依然存在问题,那就是大量promise.all以及promise依赖实例化后的大量请求,缺少并发控制。导致tcp连接数到了上限,堆积了无数的调用栈引起内存泄漏。(通过 async-pool 控制并发就可以处理)
SSR的优化策略三:区分登录态
在通过 robots.txt 以及 sitemap 等等SEO优化手段后,搜索引擎爬虫同时也会提高服务端渲染的压力。但是搜索引擎爬虫不会存在登录态,对非登录态的用户可以采用直出的服务,带登录态的用户可以提供客户端渲染的方式。在保障SEO的同时依然可以减少服务端渲染压力。(参考juejin的实现)
SSR的优化策略四:负载和自动扩缩容
nginx 集群
通过 nginx 负载处理,适合的架构模型: nginx -> N * ECS -> N * instance Node(PM2)
PM2的负载均衡
PM2自身的cluster模式,这个不做赘述
容器化集群(k8s)

- 在SVC侧,kube-proxy为SVC提供cluster内部的服务发现和负载均衡
- hpa 自动缩扩容
其他
- LRU Cache 虽好,但有缺陷。