0%

SocketIO深度改造之旅-使用篇-1

正文#

1、使用篇

SocketIO使用,不同场景上可以通过不同的技术栈组件匹配不同的场景和改造方向,本篇主要介绍一些基础的SocketIO概念和接入,大致思路入思维导图所示:

img

(图1-1)默认协议接入流程时序图

1.1 初步使用时的一些小姿势

img

(图1-2)默认协议接入流程时序图

前端通过简单的io.connect完成一次Demo连接

1
2
3
var socket =  io.connect('http://localhost:9092', {
transports: ['websocket']
});

默认的连接大致分为三步

  1. 连接获取sid
  2. 默认握手返回

img

(图1-3)Http升级Ws成功的响应

  1. sid再连接+升级到ws

在源码层,一个会话有多个channel,分别用于多种协议交互,client会随机使用一个端口和socketio服务器进行连接

1.2 通信事件的定义

1
2
3
4
5
6
7
'CONNECT',
'DISCONNECT',
'EVENT',
'ACK',
'ERROR',
'BINARY_EVENT',
'BINARY_ACK'

1.3 连接参数定义

参考socketio.js, line 1882: function Manager(uri, opts)

1
2
3
4
5
6
7
8
9
10
11
this.reconnection(opts.reconnection !== false);
this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
this.reconnectionDelay(opts.reconnectionDelay || 1000);
this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
this.randomizationFactor(opts.randomizationFactor || 0.5);
this.backoff = new Backoff({
min: this.reconnectionDelay(),
max: this.reconnectionDelayMax(),
jitter: this.randomizationFactor()
});
this.timeout(null == opts.timeout ? 20000 : opts.timeout);

1.4 接入和安全协议

HTTPDNS、浏览器下https降级和ip策略,HTTPDNS对于移动设备基本上已经是标配了,不可控因素在于LocalDNS的一致性同步问题,阿里云和腾讯云DNSPort都已经提供快捷接入方式。

https/wss降级主要针对DNS劫持后的自保手段,在能接受一定安全降级的情况下使用IP接入,是降级策略的前提。

多域名也是DNS防劫持手段之一,这是在多通配符证书的价格面前,需要掂量投入产出比。

价格参考:阿里云1年的多域名通配符,假设20台服务器,配置3个域名,需要60个域名证书支持。

img

(图1-3)阿里云多通配符域名价格参考

1.5 集群化部署与集群灰度

集群化部署跟公司整体现有技术栈对接即可,最大问题在于准备阶段需要做到可控的上线监听,如果端口通信开放,而系统还处于未完全准备阶段,会造成不可预测的结果,实例级别灰度通常需要跟接入流程息息相关,此时需要一个前置LB服务负责Socket实例的负载,一般能做到Zone+Region级别能够满足绝大部分场景。

JVM对内存配置比例参考:

堆内存+ 线程数*线程栈 + MetaSpace + 二进制代码 + 堆外内存


2G + 1024 * 256k + 256M + 48/240M + (~1G) = ~4G (3G)

1.6 双向Ack消息

理解Ack的源码实现逻辑,对于开发Ack逻辑业务有着很大的帮助。

a)用户消息发送到socketio的Ack实现

AckReuest

前端会生成一个ackId

originalPacket.getAckId()

b)发送到client的Ack实现

前端收到消息会发送Ack消息:

1
2
3
4
if (packet.getSubType() == PacketType.ACK
|| packet.getSubType() == PacketType.BINARY_ACK) {
ackManager.onAck(client, packet);
}

2层映射

AckManager.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final CancelableScheduler scheduler;
private final ConcurrentMap<UUID, AckEntry> ackEntries = PlatformDependent.newConcurrentHashMap();

class AckEntry {

final Map<Long, AckCallback<?>> ackCallbacks = PlatformDependent.newConcurrentHashMap();
final AtomicLong ackIndex = new AtomicLong(-1);

public long addAckCallback(AckCallback<?> callback) {
long index = ackIndex.incrementAndGet();
ackCallbacks.put(index, callback);
return index;
}
...
}

1.7 初步对接账户系统

UserRouter

解决问题:对接公司账户系统、多端(手机、PC/Mobile)登录

1.8 补齐前端Track

  • 获取LoadBlance地址
  • 上报连接参数和环境、设备指纹信息
  • 请求连接过程(列表尝试过程、降级过程)
  • 加入room、退出room
  • RTT-PingPong上报延迟