開放、平等、協(xié)作、快速、分享
WebSocket 協(xié)議給我們提供了一個(gè)創(chuàng)建可以支持客戶端和服務(wù)端進(jìn)行雙向?qū)崟r(shí)通信的web應(yīng)用程序的方法。相比之前使用的方法,WebSocket(作為HTML5的一部分)可以使我們更容易開的發(fā)出這種類型的應(yīng)用程序。絕大多數(shù)的現(xiàn)代瀏覽器都支持WebSocket,包括火狐,IE,Chrome,Safari以及Opera等,同時(shí),越來越多的服務(wù)端框架也開始支持WebSocket了。
對于企業(yè)應(yīng)用來說,我們需要多個(gè)WebSocket服務(wù)器來保障性能和高可用性,因此我們迫切的需要對WebSocket協(xié)議進(jìn)行負(fù)載均衡。NGINX自從1.3版本就開始支持WebSocket了,并且可以為WebSocket應(yīng)用程序做反向代理和負(fù)載均衡。
WebSocket 和HTTP協(xié)議不同,但是WebSocket中的握手和HTTP中的握手兼容,它使用HTTP中的Upgrade協(xié)議頭將連接從HTTP升級到WebSocket。這使得WebSocket程序可以更容易的使用現(xiàn)已存在的基礎(chǔ)設(shè)施。例如,WebSocket可以使用標(biāo)準(zhǔn)的HTTP端口 80 和 443,因此,現(xiàn)存的防火墻規(guī)則也同樣適用。
一個(gè)WebSockets的應(yīng)用程序會(huì)在客戶端和服務(wù)端保持一個(gè)長時(shí)間工作的連接。用來將連接從HTTP升級到WebSocket的HTTP升級機(jī)制使用HTTP的Upgrade和Connection協(xié)議頭。反向代理服務(wù)器在支持WebSocket方面面臨著一些挑戰(zhàn)。一項(xiàng)挑戰(zhàn)是WebSocket是一個(gè)hop-by-hop協(xié)議,所以,當(dāng)代理服務(wù)器攔截到一個(gè)客戶端發(fā)來的Upgrade請求時(shí),它(指服務(wù)器)需要將它自己的Upgrade請求發(fā)送給后端服務(wù)器,也包括合適的請求頭。此外,由于WebSocket連接是長時(shí)間保持的,所以代理服務(wù)器需要允許這些連接處于打開狀態(tài),而不是像對待HTTP使用的短連接那樣將其關(guān)閉。
NGINX 通過在客戶端和后端服務(wù)器之間建立起一條隧道來支持WebSocket。為了使NGINX可以將來自客戶端的Upgrade請求發(fā)送給后端服務(wù)器,Upgrade和Connection的頭信息必須被顯式的設(shè)置。如下所示:
location /wsapp/ { proxy_pass http://wsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
一旦我們完成以上設(shè)置,NGINX就可以處理WebSocket連接了。
NGINX Websockets 舉例
這里有一個(gè)展示NGINX如何為WebSocket做代理的實(shí)例。這個(gè)例子將會(huì)使用node.js上的一個(gè)實(shí)現(xiàn)了WebSocket的模塊——ws。這個(gè)示例在Ubuntu 13.10 和 CentOS 6.5上測試通過,但對于其他系統(tǒng)來說也許需要稍作修改。就這個(gè)例子來說,WebSocket服務(wù)器的IP地址是192.168.100.10,NGINX服務(wù)器的IP地址是192.168.100.20。如果你還沒有安裝node.js和npm,你可以通過以下命令安裝:
對 Debian/Ubuntu 來說:
sudo apt-get install nodejs npm
對 RHEL/CentOS 來說:
sudo yum install nodejs npm
在Ubuntu上,node.js會(huì)被安裝為 "nodejs",在CentOS中被會(huì)安裝為"node"。我們在這例子中統(tǒng)一使用"node",所以,我們將會(huì)在Ubuntu上創(chuàng)建一個(gè)連接來允許我們使用“node”:
ln -s /usr/bin/nodejs /usr/local/bin/node
然后安裝 ws:
sudo npm install ws
注意:如果你得到了一個(gè)錯(cuò)誤:“Error: failed to fetch from registry: ws” ,那么運(yùn)行下面的命令應(yīng)該能解決這個(gè)問題:
sudo npm config set registry http://registry.npmjs.org/
接下來,你可以再次運(yùn)行 sudo npm install ws
ws命令來自/root/node_modules/ws/bin/wscat,我們將會(huì)把它當(dāng)做我們的客戶端,但是我們需要?jiǎng)?chuàng)建一個(gè)程序來做我們的服務(wù)端。將下面的代碼保存到一個(gè)server.js文件中:
console.log("Server started");var Msg = '';var WebSocketServer = require('ws').Server , wss = new WebSocketServer({port: 8010}); wss.on('connection', function(ws) { ws.on('message', function(message) { console.log('Received from client: %s', message); ws.send('Server received from client: ' + message); }); });
這個(gè)程序可以通過下面的命令執(zhí)行:
node server.js
該程序會(huì)輸出一條初始化消息“Server started”,之后監(jiān)聽8010端口,等待客戶端的連接。它會(huì)處理收到的所有請求,并且將接收到的消息輸出在控制臺,之后向客戶端返回一條包含該消息的消息。我們希望NGINX去代理這些請求,通過下面的配置便可實(shí)現(xiàn):
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 "Upgrade"; } }
上面的配置會(huì)使NGINX監(jiān)聽8020端口,并把接收到的任何請求傳遞給后端的WebSocket服務(wù)器以便恰當(dāng)?shù)奶幚鞼ebSocket協(xié)議。我們可以使用wscat作為客戶端來測試一下:
/root/node_modules/ws/bin/wscat –connect ws://192.168.100.20:8020
上面的命令會(huì)通過NGINX代理服務(wù)器和WebSocket服務(wù)器建立連接,你可以輸入你想要發(fā)送給服務(wù)器的消息,之后服務(wù)器會(huì)返回一條消息。每當(dāng)你輸入一條消息,你應(yīng)該可以在服務(wù)端看到該消息的輸出,之后在客戶端會(huì)顯示一條來自服務(wù)端的消息。
這是一個(gè)交互示例:
Server: | Client: |
$ node server.js | |
Server started | |
wscat –connect ws://192.168.100.20:8020 | |
Connected (press CTRL+C to quit) | |
> Hello | |
Received from client: Hello | |
< Server received from client: Hello |
由此我們可以看到服務(wù)端與客戶端能夠通過作為代理的NGINX通信, 而且消息可以持續(xù)進(jìn)行雙向傳輸直到客戶端或服務(wù)端斷開連接。為了能使NGINX正確處理WebSocket, 只需正確地設(shè)置消息頭來處理更新從http到WebSocket連接的Upgrade請求。
更多信息請參見:
24小時(shí)免費(fèi)咨詢
請輸入您的聯(lián)系電話,座機(jī)請加區(qū)號