概述
经过了几天捣鼓,加上请教大牛,将自己走过的这个坑总结如下。以下代码亲测有效,工程使用的node express框架
需求分析:
因为nodejs是单线程,在实际项目运行时,一旦遇到错误,会导致整个系统崩溃,因此需要使用node的多进程模型,比如简易使用的pm2进程管理工具。在常规的http服务中,pm2直接启动工程即可(下文附上简单pm2介绍),可是一旦server中集成了socket.io服务就会导致ws通道建立失败,为什么要用socket.io呢,因为我的项目需求是前端调用后端算法,后端需要计算几分钟至几个小时的时间,然后再将计算结果显示到前端(这个就不重点介绍了)。因此我们需要解决这种问题,让socket.io充分利用多核,且保证连接成功。
为什么会出现socket.io连接失败呢?
因为pm2进程在分发请求的阶段采用了某种算法的均衡,如round-robin或者其他hash方式(但不是iphash),因此在socket.io客户端连接建立阶段发送的多个xhr请求,会被pm2定位到不同的worker进程中。前文中提到每个xhr请求都会携带sid字段标识当前连接,因此当一个携带sid字段的请求被pm2定位到另一个与该连接无关的worker时,就会造成请求失败,返回{"code":1,"message":"Session ID unknown"}错误;即使前三次xhr握手成功,进入websocket连接升级阶段,负责侦听update事件的worker也往往不是之前的那个worder,因此导致websocket连接建立失败。
简单来说就是,客户端多次请求的服务端进程不是同一个进程才导致的ws连接无法成功建立。
解决方案:nginx反向代理+iphash
1、首先nginx安装即常用命令
官方下载地址:https://nginx.org/en/download.html
Linux下安装:
先解压:tar zxvf nginx-1.15.8.tar.gz
进入解压后目录:./configure
make && make install
nginx -v 查看是否安装成功
编辑配置文件,centos系统默认在/etc/nginx/,一定要使用root权限才能编辑。
[xxxx@powermonster ~]$ nginx -v
nginx version: nginx/1.12.1
[xxxx@powermonster ~]$ sudo -i
[sudo] password for xxxx:
[root@powermonster ~]# cd /etc/nginx/
[root@powermonster nginx]# ls
conf.d koi-utf mime.types nginx.conf uwsgi_params
fastcgi_params koi-win modules scgi_params win-utf
[root@powermonster nginx]# vim nginx.conf
配置文件修改如下:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
upstream io_nodes {
ip_hash;
server 127.0.0.1:3131;
server 127.0.0.1:3132;
server 127.0.0.1:3133;
server 127.0.0.1:3134;
}
server {
listen 3000; //端口随意设置,只要是外网能访问的且不被占用的即可
server_name 12.34.56.78; //这是你自己的服务器IP地址,我这随意写了一个
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_pass http://io_nodes;
}
}
}
常用命令:
测试配置文件是否正确:
[root@powermonster]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@powermonster]#nginx -s reload # 重新载入配置文件
[root@powermonster]#nginx -s reopen # 重启 Nginx
[root@powermonster]#nginx -s stop # 停止 Nginx
若nginx安装成功,则http://12.34.56.78:3000/能够访问,页面有nginx版本提示。
2、pm2安装配置
pm2 是一个带有负载均衡功能的Node应用的进程管理器。可以把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远都活着,0秒的重载。
pm2的主要特性:
1、内建负载均衡(使用Node cluster 集群模块)
2、后台运行
3、0秒停机重载
4、具有Ubuntu和CentOS 的启动脚本
5、停止不稳定的进程(避免无限循环)
6、控制台检测
7、提供 HTTP API
8、远程控制和实时的接口API ( Nodejs 模块,允许和PM2进程管理器交互 )
pm2的安装:
npm install -g pm2
接下来新建一个pm2.json,将该文件放置到你要运行的工程根目录下,如图所示:
pm2.json内容如下:
"apps": [
{
"name": "ws",
"script": "./app.js",
"env": {
"NODE_ENV": "development"
},
"env_production": {
"NODE_ENV": "production"
},
"instances": 4,
"exec_mode": "cluster",
"max_restarts" : 3,
"restart_delay" : 5000,
"log_date_format" : "YYYY-MM-DD HH:mm Z",
"combine_logs" : true
}
]
}
3、接下来要改动你的工程代码了,app.js以及调用socket的HTML文件
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var app = express();
var server = require('http').Server(app),
port = 3131 + parseInt(process.env.NODE_APP_INSTANCE),
io = require('socket.io')(server);
io
.on('connection', function(socket) {
socket.on('disconnect', function() {
console.log('/: disconnect-------->')
});
socket.on('handle_event', function() {
socket.emit('return_event', '/: '+port);
console.log('/: '+port)
});
});
io.of('/ws')
.on('connection', function(socket) {
socket.on('disconnect', function() {
console.log('disconnect-------->')
});
socket.on('handle_event', function() {
socket.emit('return_event', port);
});
});
app.set('port', port);
server.listen(port);
module.exports = app;
例如在index.html中调用socket,则代码如下:
<script>
var btn = document.getElementById('btn1');
btn.addEventListener('click',function(){
var socket = io.connect('http://12.34.56.78/ws',{
reconnection: false
});
var data={a:1};
socket.on('connect',function(){
// 发送数据
socket.emit('handle_event',data);
//接收数据
socket.on('return_event',function(d){
console.log(d);
});
});
socket.on('error',function(err){
console.log(err);
})
});
</script>
4、最后就是pm2运行node工程啦
话不多说,上图,内含常用pm2指令
看到上面的界面,表明你的部署正常,可以http://12.34.56.78:3000/访问页面啦
初级前端,还请路过的大牛指教。。
最后
以上就是阔达柜子为你收集整理的node pm2 + nginx 部署websocket项目解决方案--超详细总结的全部内容,希望文章能够帮你解决node pm2 + nginx 部署websocket项目解决方案--超详细总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复