本站使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或從新修改使用,但須要註明來源。 署名 4.0 國際 (CC BY 4.0)html
本文做者: 蘇洋node
建立時間: 2018年09月04日 統計字數: 4350字 閱讀時間: 9分鐘閱讀 本文連接: soulteary.com/2018/09/04/…git
提及 Node.js
的 WebSocket
方案,可選的方案有許多種,其中許多方案都提供將 WS
服務端口和 HTTP
服務複用的方案,然而這種方案真的是最佳選擇嗎。github
不管是專業作實時通訊的 socket.io ,仍是用戶量最大的 Express
的熱門中間件 express-ws 都支持端口複用,好比 WS
和 HTTP
複用 80
端口, WSS
和 HTTPS
複用 443
端口。web
這裏以 express-ws
底層封裝的 ws 庫爲例,來簡單剖析,socket.io
實現相似不過度層較多,有興趣能夠圍觀代碼。ajax
不過在聊 Traefik
以前,咱們先得聊聊 Node.js
和 Websocket
。docker
先說結論,優勢:express
HTTP
請求中的會話信息,進行簡單的驗證操做,可以代碼級複用邏輯。缺點也很明顯:編程
Express
處理仍是 WS
處理,存在性能損耗,若是須要進行壓縮等操做,會有更多的損耗。WS
服務便可,因爲耦合,不得不將整個服務進行擴展,存在更多資源的損耗。express-ws 進行端口複用的時候,會進行大量 hacks 操做,包括擴展路由、改寫請求地址添加特殊標記、重寫默認響應頭...安全
下面這段示例是官方給出的端口複用的例子。
var express = require('express');
var app = express();
var expressWs = require('express-ws')(app);
app.use(function (req, res, next) {
console.log('middleware');
req.testing = 'testing';
return next();
});
app.get('/', function(req, res, next){
console.log('get route', req.testing);
res.end();
});
app.ws('/', function(ws, req) {
ws.on('message', function(msg) {
console.log(msg);
});
console.log('socket', req.testing);
});
app.listen(3000);
複製代碼
實際使用的時候,訪問 WS
的 /
,會訪問 Express
的 /.websocket?{QUERY}
,並使用中間件注入處理過程的方式,搶在默認處理前使用 ws
替換處理過程,修改響應頭,輸出處理後的內容,並調用 res.end
結束流程。
在路由愈來愈多、請求量愈來愈多的狀況下,會存在不少沒必要要的損耗。
若是不須要端口複用,其實直接使用 ws
來監聽獨立的新端口便可,參考官方示例,能夠很輕鬆的寫出這樣一個例子:
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 8080,
perMessageDeflate: {
zlibDeflateOptions: { // See zlib defaults.
chunkSize: 1024,
memLevel: 7,
level: 3,
},
zlibInflateOptions: {
chunkSize: 10 * 1024
},
// Other options settable:
clientNoContextTakeover: true, // Defaults to negotiated value.
serverNoContextTakeover: true, // Defaults to negotiated value.
clientMaxWindowBits: 10, // Defaults to negotiated value.
serverMaxWindowBits: 10, // Defaults to negotiated value.
// Below options specified as default values.
concurrencyLimit: 10, // Limits zlib concurrency for perf.
threshold: 1024, // Size (in bytes) below which messages
// should not be compressed.
}
});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
server.listen(8080);
複製代碼
HTTP
服務監聽在另一個端口,能夠參考 Express
最簡單的示例:
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
複製代碼
這裏分別將代碼片斷進行保存,當你分別使用 Node.js
執行它的時候,你將會獲得監聽 3000
端口和 8080
端口的簡單服務,支持使用 WS
和 HTTP
進行數據交互。
優點:
劣勢:
RDS
、Redis Cache
等方案的前提下,請求之間的數據難以共享。我將 SSL
證書掛載和 HTTP
壓縮放在 Traefik
端處理,相比較 Node.js
來作,一來能夠保障業務代碼功能獨立純粹,二來性能確實不如它,並且維護起來也比較麻煩(證書管理)。
對於接入網關的服務,只要聲明提供 HTTP
和 WS
的端口和對應的域名便可,程序啓動以後,Traefik
會自動將應用掛載到對應域名上,並支持 HTTP(S)
和 WS(S)
的服務。
爲圖簡便,我將上面的代碼片斷保存爲一個基礎鏡像,交付給編排工具使用。
若是你將上面的代碼片斷保存爲一個文件,能夠試試下面的配置:
version: '3'
services:
node:
image: docker.lab.com/example.lab.com:0.0.1
restart: always
labels:
- "traefik.enable=true"
- "traefik.web.port=3000"
- "traefik.web.frontend.rule=Host:web.soulteary.com"
- "traefik.ws.port=8080"
- "traefik.ws.frontend.rule=Host:ws.soulteary.com"
networks:
- traefik
expose:
- 3000
- 8080
extra_hosts:
- "web.soulteary.com:127.0.0.1"
- "ws.soulteary.com:127.0.0.1"
networks:
traefik:
external: true
複製代碼
使用上面的配置運行以後,你會發現本來的 3000
端口和 8080
端口,都被「改寫」成爲了 80
和 443
端口上了,Web 應用使用的時候,便不用額外寫入「醜陋」的端口號了,可是這樣的配置不利於服務擴展,在端口複用優劣小節中我提到過。
那麼,若是你有意將代碼進行拆分,那麼能夠試試下面的配置:
version: '3'
services:
web:
image: docker.lab.com/example.lab.com:0.0.1
restart: always
labels:
- "traefik.enable=true"
- "traefik.web.port=3000"
- "traefik.web.frontend.rule=Host:web.soulteary.com"
networks:
- traefik
expose:
- 3000
extra_hosts:
- "web.soulteary.com:127.0.0.1"
ws:
image: docker.lab.com/example.lab.com:0.0.1
restart: always
labels:
- "traefik.enable=true"
- "traefik.ws.port=8080"
- "traefik.ws.frontend.rule=Host:ws.soulteary.com"
networks:
- traefik
expose:
- 8080
extra_hosts:
- "ws.soulteary.com:127.0.0.1"
networks:
traefik:
external: true
複製代碼
擴容也很簡單,若是你要以 2:3 的比例運行不一樣協議的話,只須要:
docker-compose scale web=2 ws=3
複製代碼
若是你還在使用 ajax polling
或許這個方案能夠給你更好的體驗。
若是你對 Traefik 指望有更多的瞭解,也歡迎和我溝通討論。
我如今有一個小小的折騰羣,裏面彙集了一些喜歡折騰的小夥伴。
在不發廣告的狀況下,咱們在裏面會一塊兒聊聊軟件、HomeLab、編程上的一些問題,也會在羣裏不按期的分享一些技術沙龍的資料。
喜歡折騰的小夥伴歡迎掃碼添加好友。(請註明來源和目的,不然不會經過審覈) 關於折騰羣入羣的那些事