.next项目服务端渲染部署中的负载均衡实现

1,279 阅读2分钟

我这里主要整理下.next如何部署到线上,至于基础的服务端ssr渲染,和.next项目如何开发,掘金这里其他的文章已经写的很全了,我就不多赘述了。

和spa单页面应用部署不同,.next是服务端渲染的项目,页面和初始页面展示的内容都是在服务端完成了,我项目里node请求用的isomorphic-unfetch这个库。

  1. 首先和spa项目一样,next build,生成的.next目录就是打包后的包,相当于spa中的build目录
  2. 把.next目录上传到server上,在服务器上执行next start --port 10001
  3. 配nginx,把测试域名指向10001端口
  4. 本地配服务的host就可以访问了

几个tips

  1. 在服务端跑next,需要在服务器上安装node、openresty那些环境和依赖
  2. 在服务器上跑next start,其实本质就是把本地的next start一整套给挪到服务器上一样的

上面的这个流程只是最简单的跑个demo,并不能通过ab压测,下面我再介绍下我这边实现的负载均衡

  1. 全局安装pm2(node进程保护),项目下安装concurrently(启多个node进程)
  2. 新建一个deploy.js,然后拷贝下面的代码,目的是在server上启动24个端口的进程,
  3. 项目下执行pm2 start deploy.js -i max --name lemon-web 这行代码的含义是,以集群模式部署,并且已当前机器有几个CPU就启动几个进程,我的开发机是4核,就启了4个进程,如下图
  4. nginx配置里添加upstream,完成负载均衡

如上配置完成后,我们线上的server有主备两台机器,都是24核的CPU,ab测试的话,同时并发2k会卡主,但是不会卡死,node渲染任务会逐步吞吐。


deploy.js

let cmd=require('node-cmd');
let executeCmd = "concurrently";
const portStart = 10001;
const portEnd = 10024;
for (let i=portStart; i<=portEnd; i++){
	let temp = ` "next start --port ${i}"`;
	executeCmd += temp;
}
// let executeCmd = "concurrently \"next start --port 10001\" \"next start --port 10002\" \"next start --port 10003\"";
// console.log(executeCmd)
cmd.run(executeCmd);
console.log("success");

nginx配置

upstream nodesrv {
    server 127.0.0.1:10001;
    server 127.0.0.1:10002;
    server 127.0.0.1:10003;
    ...
    server 127.0.0.1:10024;
}

server {
    ...
    location ~ .*\.(?:js|css|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
    {
        expires      7d; 
        proxy_pass   http://nodesrv;   
        ...
    }
    ...
}

package.json

{
  ...
  "scripts": {
    ...
    "deploy": "pm2 start deploy.js -i max --name lemon-web"
  }
}

现阶段这个实现能抗住2~3k的并发吞吐,后续的提高我也有想过。

我有做过测试,性能上的消耗主要在node在服务端fetch数据这块,页面本身的node渲染其实非常地快。由于我们的业务逻辑比较复杂,调用的接口比较多,针对这个问题,我有想出两个方案

  1. 写个定时器把数据缓存到一个json文件里,然后页面直接从静态json当中读取,这样性能就能提高不少
  2. 在server上定时把项目export成静态页面

这两个方法本质上都是把node的fetch数据做了缓存,具体等后面项目量起来我再做这个优化。