Skip to content

Commit 4a30fdc

Browse files
committed
update 2019年7月20日16:22:23
1 parent 613b3c6 commit 4a30fdc

File tree

7 files changed

+205
-0
lines changed

7 files changed

+205
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## 解析器/协议 差异
2+
3+
这只与用其他语言更新socket.io实现、自定义socket.io客户机等相关。
4+
5+
### 差异1 - 数据包编码
6+
7+
解析现在是基于类和异步的。不是返回单个编码字符串,而是使用一个编码数组作为唯一参数对调用回调进行编码。每个编码都应该按顺序写入传输。这更灵活的让二进制数据传输,下面是一个例子:
8+
9+
```js
10+
const encoding= parser.encode(packet);
11+
console.log(encoding); //完全编码的数据包
12+
```
13+
14+
VS:
15+
```js
16+
const encoder= new parser.Encoder();
17+
encoder.encode(packet,encodings=>{
18+
for(let i=0;i<encodings.length;i++){
19+
console.log(encodings[i]) //包的编码部分
20+
}
21+
})
22+
```
23+
24+
### 差异2 - 数据包解码
25+
26+
解码将使事情进一步发展,并且是基于事件的。这是因为某些对象(包含二进制)同时在多个部分中进行编码和解码。这个例子应该有助于理解:
27+
28+
```js
29+
const packet= parser.decode(decoding);
30+
console.log(packet) // 要处理的成型socket.io包
31+
32+
```
33+
VS:
34+
35+
36+
```js
37+
const decoder= new parser.Decoder();
38+
decoder.on('decoded',(packet)=>{
39+
console.log(packet) // 要处理的成型socket.io包
40+
})
41+
42+
decoder.add(encodings[0]) // encodings 是从传输接收的两个编码的数组
43+
decoder.add(encodings[1]) // 添加最后一个元素后,解码器将发出“decoded”
44+
```
45+
46+
###
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Apache HTTPD 配置
2+
3+
```xml
4+
Header add Set-Cookie "SERVERID=sticky.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
5+
6+
<Proxy "balancer://nodes_polling">
7+
BalancerMember "http://app01:3000" route=app01
8+
BalancerMember "http://app02:3000" route=app02
9+
BalancerMember "http://app03:3000" route=app03
10+
ProxySet stickysession=SERVERID
11+
</Proxy>
12+
13+
<Proxy "balancer://nodes_ws">
14+
BalancerMember "ws://app01:3000" route=app01
15+
BalancerMember "ws://app02:3000" route=app02
16+
BalancerMember "ws://app03:3000" route=app03
17+
ProxySet stickysession=SERVERID
18+
</Proxy>
19+
20+
RewriteEngine On
21+
RewriteCond %{HTTP:Upgrade} =websocket [NC]
22+
RewriteRule /(.*) balancer://nodes_ws/$1 [P,L]
23+
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
24+
RewriteRule /(.*) balancer://nodes_polling/$1 [P,L]
25+
26+
ProxyTimeout 3
27+
```
28+
29+
[例子](https://github.com/socketio/socket.io/tree/master/examples/cluster-httpd)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## HAProxy 配置
2+
3+
```plain
4+
# Reference: http://blog.haproxy.com/2012/11/07/websockets-load-balancing-with-haproxy/
5+
6+
listen chat
7+
bind *:80
8+
default_backend nodes
9+
10+
backend nodes
11+
option httpchk HEAD /health
12+
http-check expect status 200
13+
cookie io prefix indirect nocache # using the `io` cookie set upon handshake
14+
server app01 app01:3000 check cookie app01
15+
server app02 app02:3000 check cookie app02
16+
server app03 app03:3000 check cookie app03
17+
18+
```
19+
20+
[例子](https://github.com/socketio/socket.io/tree/master/examples/cluster-haproxy)
21+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Nginx 配置
2+
3+
`nginx.conf`文件的`http {}`部分中,您可以使用要在以下两者之间平衡负载的socket.io进程列表声明`upstream`部分:
4+
5+
```nginx
6+
http{
7+
server{
8+
listen 3000;
9+
server_name io.yourhost.com;
10+
11+
location / {
12+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
13+
proxy_set_header Host $host;
14+
15+
proxy_pass http://nodes;
16+
17+
# 启用websockets
18+
proxy_http_version 1.1;
19+
proxy_set_header Upgrade $http_upgrade;
20+
proxy_set_header Connection "upgrade";
21+
22+
23+
}
24+
}
25+
upstream nodes {
26+
# 基于IP启用粘性会话
27+
ip_hash;
28+
server app01:3000;
29+
server app02:3000;
30+
server app03:3000;
31+
32+
}
33+
}
34+
35+
```
36+
37+
请注意`ip_hash`指令,它指示连接将是粘性的。
38+
39+
确保在最顶层配置`worker_process`,以指示nginx应该使用多少worker。您还可能希望调整`events {}`块中的`worker_connections`设置。
40+
41+
[例子](https://github.com/socketio/socket.io/tree/master/examples/cluster-nginx)
42+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## 在节点之间传递事件
2+
3+
既然您有多个Socket.IO节点可以接受连接,那么如果您想向每个人(甚至是某个 [房间](https://socket.io/docs/rooms-and-namespaces/#Rooms) 中的每个人)广播事件,那么就需要在进程或计算机之间传递消息。
4+
5+
负责路由消息的接口就是我们所称的`Apdapter`。您可以在 [socket.io-adapter](https://github.com/socketio/socket.io-adapter) 上实现自己的(通过从socket.io-adapter继承),也可以使用我们在[redis](https://redis.io/)上提供的:[socket.io-redis](https://github.com/socketio/socket.io-redis):
6+
7+
```js
8+
9+
const io = require('socket.io')(3000)
10+
const redis = require('socket.io-redis');
11+
io.adapter(redis({host:"localhost",port:6379}));
12+
13+
```
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## 粘性负载均衡
2+
3+
如果计划在不同的进程或机器之间分配连接负载,则必须确保与特定会话ID关联的请求连接到发起它们的进程。
4+
5+
6+
这是由于某些传输(如xhr轮询或jsonp轮询)依赖于在“socket”的生命周期内触发多个请求。如果不启用粘性负载均衡,这将导致很可怕:
7+
8+
9+
```txt
10+
11+
Error during WebSocket handshake: Unexpected response code: 400
12+
13+
```
14+
15+
这意味着升级请求被发送到一个未知socket id的节点,因此是HTTP 400响应。
16+
17+
为了说明为什么需要这样做,请考虑向所有连接的客户机发出事件的示例:
18+
19+
```js
20+
21+
io.emit('hi',"all sockets")
22+
23+
```
24+
25+
很有可能这些客户机中的一些可能有一个活动的双向通信通道,比如`WebSocket`,我们可以立即对其进行写入,但其中一些客户机可能正在使用长轮询。
26+
27+
如果他们使用的是长轮询,那么他们可能已经或可能没有发送一个我们可以写入的请求。他们可能在这些请求之间。在这些情况下,这意味着我们必须在进程中缓冲消息。为了让客户机在发送请求时成功地声明这些消息,最简单的方法是将连接路由到同一进程。
28+
29+
30+
如上所述,`WebSocket`传输没有这个限制,因为基础TCP连接在客户机和给定服务器之间保持打开状态。这就是为什么你可能会找到一些只使用`WebSocket`传输的建议:
31+
32+
33+
```js
34+
const client = io('https://io.yourhost.com',{
35+
//警告:在这种情况下,没有回滚到长轮询
36+
transports:["websocket"] // 或者 [ 'websocket', 'polling' ], 这两者都一样
37+
})
38+
```
39+
40+
这两种方法都意味着,当无法建立WebSocket连接时,不会出现长轮询回退,这实际上是socket.io的关键功能之一。在这种情况下,您应该考虑使用原始[WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket),或者像[robust-WebSocket](https://github.com/appuri/robust-websocket)那样的包装器。
41+
42+
43+
为了实现粘性会话,有两个主要解决方案:
44+
45+
- 基于起始地址路由客户端
46+
- 基于cookie路由客户端
47+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## 使用Node.js集群
2+
3+
与nginx一样,node.js也通过`cluster`模块提供了内置的集群支持。
4+
5+
Fedor Indutny创建了一个名为[Sticky Session](https://github.com/indutny/sticky-session)的模块,该模块确保文件描述符(即:连接)基于`remoteAddress`(即:IP)进行路由。请注意,这可能会导致路由不平衡,这取决于散列方法。
6+
7+
您还可以根据集群工作进程ID为集群中的每个工作进程分配不同的端口,并使用上面可以找到的配置来平衡负载。

0 commit comments

Comments
 (0)