本站使用「署名 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、编程上的一些问题,也会在群里不按期的分享一些技术沙龙的资料。
喜欢折腾的小伙伴欢迎扫码添加好友。(请注明来源和目的,不然不会经过审核) 关于折腾群入群的那些事