「应用中间件」使用NGINX作为WebSocket代理
温馨提示:这篇文章已超过491天没有更新,请注意相关的内容是否还可用!
WebSocket 协议提供了一种创建支持客户端和服务器之间实时双向通信的 Web 应用程序的方法。 作为 HTML5 的一部分,WebSocket 使开发这些类型的应用程序比以前可用的方法容易得多。 大多数现代浏览器都支持 WebSocket,包括 Chrome、Firefox、Internet Explorer、Opera 和 Safari,现在越来越多的服务器应用程序框架也支持 WebSocket。
对于需要多个 WebSocket 服务器来实现性能和高可用性的企业生产,需要一个理解 WebSocket 协议的负载均衡层。 NGINX 从 1.3 版本开始支持 WebSocket,可以作为反向代理对 WebSocket 应用进行负载均衡。 (所有版本的 NGINX Plus 都支持 WebSocket。)
查看最近关于 NGINX 可扩展性的性能测试,以平衡 WebSocket 连接。
WebSocket协议不同于HTTP协议代理服务器,但是WebSocket握手是兼容HTTP的,使用HTTP升级工具将连接从HTTP升级到WebSocket。 这使得 WebSocket 应用程序更容易适应现有的基础设施。 例如,WebSocket 应用程序可以使用标准的 HTTP 端口 80 和 443,从而允许使用现有的防火墙规则。
WebSocket 应用程序通过维护客户端和服务器之间的长期连接来促进实时应用程序的开发。 将连接从 HTTP 升级到 WebSocket 的 HTTP 升级机制使用 Upgrade 和 Connection 标头。 反向代理服务器在支持 WebSocket 方面面临一些挑战。 一是WebSocket是逐跳协议,因此当代理服务器拦截到客户端的升级请求时,需要将自己的升级请求发送给后端服务器,包括相应的标头。 此外,由于 WebSocket 连接是长寿命的,而不是 HTTP 使用的典型的短寿命连接,反向代理需要允许这些连接保持打开状态,而不是因为它们看起来空闲而关闭它们。
NGINX 支持 WebSockets,允许在客户端和后端服务器之间建立隧道。 为了让 NGINX 将升级请求从客户端发送到后端服务器,必须显式设置升级和连接标头,如以下示例所示:
location /wsapp/ { proxy_pass http://wsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; }
这样做之后,NGINX 将其作为 WebSocket 连接进行处理。
NGINX 网络套接字示例
下面是一个实例,展示了 NGINX 如何作为 WebSocket 代理工作。 此示例使用 ws,一个基于 Node.js 的 WebSocket 实现。 NGINX 使用 ws 和 Node.js 作为简单 WebSocket 应用程序的反向代理。 这些说明已经在 Ubuntu 13.10 和 CentOS 6.5 上进行了测试,但可能需要针对其他操作系统和版本进行调整。 本例中WebSocket服务器的IP地址为192.168.100.10,NGINX服务器的IP地址为192.168.100.20。
如果未安装 Node.js 和 npm,请运行以下命令:
Debian 和 Ubuntu:
$ sudo apt-get 安装 nodejs npm
对于 RHEL 和 CentOS:
$ sudo yum 安装 nodejs npm
Node.js 在 Ubuntu 上安装为 nodejs,在 CentOS 上安装为 node。 这个例子使用 node,所以在 Ubuntu 上我们需要创建一个从 nodejs 到 node 的符号链接:
$ ln -s /usr/bin/nodejs /usr/local/bin/node
要安装 ws,请运行以下命令:
$ 须藤 npm 安装 ws
注意:如果您收到错误消息:“error: failed to fetch from registry: ws”,请运行以下命令来解决问题:
须藤 npm 配置设置注册表
然后再次运行 sudo npm install ws 命令。
ws 自带程序 /root/node_modules/ws/bin/wscat 将用作客户端,但我们需要创建一个程序作为服务器。 使用以下内容创建一个名为 server.js 的文件:
console.log("服务器启动");
var 消息 = '';
var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({端口: 8010});
wss.on('连接', 函数(ws) {
ws.on('消息', 函数(消息) {
console.log('从客户端收到:%s', message);
ws.send('服务器从客户端收到:' + message);
});
});
要执行服务器程序代理服务器,请运行以下命令:
$节点服务器.js
服务器打印一条初始的“服务器已启动”消息,然后侦听端口 8010,等待客户端连接到它。 当它收到客户端请求时,它会回应它并向客户端发送一条消息,其中包含它收到的消息。 为了让 NGINX 代理这些请求,我们创建了以下配置:
http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream websocket { server 192.168.100.10:8010; } server { listen 8020; location / { proxy_pass http://websocket; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } } }
NGINX 侦听端口 8020 并将请求代理到后端 WebSocket 服务器。 proxy_set_header 指令使 NGINX 能够正确处理 WebSocket 协议。
为了测试服务器,我们将 wscat 作为客户端运行:
$ /root/node_modules/ws/bin/wscat --connect ws://192.168.100.20:8020
wscat 通过 NGINX 代理连接到 WebSocket 服务器。 当您键入 wscat 想要发送到服务器的消息时,您将看到它在服务器上回显,然后来自服务器的消息出现在客户端上。 这是一个交互式示例:
服务器:客户端:$节点server.js
服务器启动
wscat --connect ws://192.168.100.20:8020
已连接(按 CTRL+C 退出)
> HelloReceived from client: Hello < Server received from client: 你好
在这里我们看到客户端和服务器能够通过 NGINX 进行通信,NGINX 充当代理并且可以继续来回发送消息,直到客户端或服务器断开连接。 NGINX 正确处理 WebSockets 所需的全部是正确设置标头以处理将连接从 HTTP 升级到 WebSocket 的升级请求。
原来的:
本文:
讨论:请加入知识星球或小红圈【首席架构师圈】