网站做推广需要营业执照,杭州建网站哪家口碑好,免费电视剧在线观看,域度设计网站HubuIM RFC草案
消息协议设计
基本协议
评估标准 【性能】协议传输效率#xff0c;尽可能降低端到端的延迟#xff0c;延迟高于200ms用户侧就会有所感知 【兼容】既要向前兼容也要向后兼容 【存储】减少消息包的大小#xff0c;降低空间占用率#xff0c;一个字节在亿…HubuIM RFC草案
消息协议设计
基本协议
评估标准 【性能】协议传输效率尽可能降低端到端的延迟延迟高于200ms用户侧就会有所感知 【兼容】既要向前兼容也要向后兼容 【存储】减少消息包的大小降低空间占用率一个字节在亿级别并发之下也是一亿个字节 【计算】减少编解码时造成的CPU使用率的权衡 【网络】尽可能减少网络带宽消耗 【安全】协议安全性 【迭代】要能够快速迭代灵活拓展 【通用】可跨平台接入H5IoT设备等等 【可读】
基本结构
IM协议的设计从纵向来看分为三个层次应用层/安全层/传输层。
应用层
有很多开源协议例如MQTTwebsocket等等。但是这些协议冗余的字段比较多在大型IM的场景下一般都是自定义协议的。
因此HubuIM采用自定义协议
序列化方式使用protobuf这个是无可争议的。
安全层
基于密钥的生命周期可以分为 TLS/SSL加密效果好证书的管理比较复杂 固定加密通信前客户端和服务端约定好密钥和加密算法会被黑客逆向 一人一密使用用户特定的属性进行加密例如密码 一次一密这个是最安全的创建连接建立一次会话双方进行加密三次握手非对称对称加密传输。
加密消耗的是CPU资源是CPU密集型操作。如果放到接入层或者业务逻辑层来做的话会影响到他们的正常运行。因此应该在四层网络负载或者七层网络负载的地方去解密内网环境默认是安全的。 因此HubuIM采用的方式是TLS3.0网关终止。 在Nginx处就进行解密Nginx所在的机器可以使用硬件来进行优化例如用GPU加速用Intel加速器等等。
那么为什么不在LVS四层网络负载均衡器上面去做加密解密然后直接发到IM网关这样可以让网络通信少跳一次。
这个问题是因为Nginx这个七层负载均衡的地方相当于是公司的一个基础架构层是要做很多事情的不方便去掉的。
传输层
可以使用UDP或者TCP协议。微信这种很定义的可能使用UDPQUIC这种保证可靠性。因为UDP是无状态的传输协议不会存储连接的状态在弱网环境下更优消息风暴发生的可能性更小。
UDP的话需要在应用层写大量的代码来保证可靠性难度非常大因此HubuIM使用TCP协议。弱网环境在应用层来进行优化。
总结
HubuIM协议
对于传输层使用TCP安全层使用TLS应用层使用自研二进制协议开源序列化协议。
既然使用了TCP协议那么我们面临的一个问题就是TCP的粘包拆包问题。具体解决方法我们在后面讲解。
消息可用性
基本概念 长链接 vs 短链接。我们才用的是长链接和短链接共同作用短链接作为旁路。 各种ID connID代表的是一个TCP链接 clientID代表的是client发送给IM Server的用来标识本客户端消息发送顺序的ID仅仅是本客户端该ID并不代表消息的全局一致。需要有递增性质。 seqID当IM Server收到clientID之后生成的会话内消息顺序一致的seqID。需要有递增性质。 sessionID会话ID msgID代表的是一个消息的ID PULL 与 PUSH 模式。PULL就是client向IM Server拉取消息使用短链接减少TCP链接的压力。PUSH就是IM Server通过TCP长链接推送消息。 通信复杂度网络传输过程中经过的节点可以说是一个性能瓶颈不能经过太多节点。消息风暴就是网络中有太多的报文会压垮IDC。常见于弱网环境弱网下消息丢失严重TCP的可靠性反而成为延迟让网络中有大量的报文。
背景介绍
对于IM来说消息的可靠与一致就是可达有序不重不漏。
有人会问TCP已经保证一致性了那么为什么IM还有保证一致。
其实答案很简单TCP只能保证到内核传输层为止的可靠性但是应用层的可靠性你是没有办法保证的。
设计IM必须有端到端的设计思维底层可靠不等于上层可靠底层一致不等于上层一致。
方案选型
技术挑战是什么 三方通信网络层面无法保证消息必达 没有全局时钟确定唯一顺序并且是符合因果顺序的 多客户发送/多服务端接收/多线程多协程处理顺序难以确定。
解决方案是学习TCP 消息及时服务端实时接收消息并实时在线发送 消息可达超时重试ACK确认 消息幂等分配seqID服务端存储seqID 消息有序seqID可以比较。
上行消息
clientID严格递增
弱网问题是传输层的问题可以优化传输层协议例如升级成Quic来优化长连接不适合在弱网环境下工作。
消息转发 seqID在会话内有序就行这样就可以解决redis的单点问题。 seqID需要在ACK之前分配否则ACK成功发出去之后服务器宕机了这样seqID就等于没有分配会出现问题。 如果服务端在存储消息业务处理接入层路由的时候失败怎么办 消息存储之后再回复ACK如果ACK失败则客户端重试时再次幂等的回复ACK。 一旦消息存储如果服务崩溃导致长连接断开客户端重新建立连接时可以发送一个pull信令拉去历史消息进行消息补洞保证可靠性。 消息存储可以交给MQ异步的进行。
下行消息
分配seqID的时候针对redis的单点使用lua脚本来进行一个ID的跳变。
客户端发现消息不连续的时候可能是因为消息跳变了但是他无法确认因此不能直接拒绝而是发送pull信令来进行增补如果拉去不到新消息则说明是跳变导致。
推拉结合长短连接结合服务端打包整流假如是一个群聊一下子有100M信息我会把这些信息放在一个窗口里面不会一个一个发送这样的批处理可以提高效率。然后窗口大了之后服务端向客户端发送一个pull信令让客户端发起一个请求来用短链接拉取这个窗口里面的数据。